From e4db48f93ead8dee189e2b5e1a5c8960bcd37c6e Mon Sep 17 00:00:00 2001 From: Containerized Agent Date: Fri, 13 Feb 2026 21:40:25 +0000 Subject: [PATCH 01/22] feat: add Grafana dashboards and metrics sync tooling Add strands-grafana directory containing: - Grafana docker-compose setup with SQLite datasource - Pre-built health and triage dashboards - strands-metrics Rust CLI for syncing GitHub org data to SQLite The metrics CLI fetches issues, PRs, reviews, comments, stars, commits, and CI workflow runs from the strands-agents org, computes daily aggregate metrics, and stores everything in a local SQLite database that Grafana reads for visualization. Migrated from chaynabors/strands (commit 0fbe13c). Co-authored-by: chaynabors --- strands-grafana/.gitignore | 5 + strands-grafana/README.md | 87 + strands-grafana/docker-compose.yaml | 20 + .../provisioning/dashboards/dashboards.yaml | 11 + .../provisioning/dashboards/health.json | 12577 ++++++++++++++++ .../provisioning/dashboards/triage.json | 676 + .../provisioning/datasources/automatic.yaml | 10 + strands-grafana/strands-metrics/Cargo.toml | 18 + .../strands-metrics/src/aggregates.rs | 215 + strands-grafana/strands-metrics/src/client.rs | 730 + strands-grafana/strands-metrics/src/db.rs | 192 + strands-grafana/strands-metrics/src/main.rs | 119 + 12 files changed, 14660 insertions(+) create mode 100644 strands-grafana/.gitignore create mode 100644 strands-grafana/README.md create mode 100644 strands-grafana/docker-compose.yaml create mode 100644 strands-grafana/provisioning/dashboards/dashboards.yaml create mode 100644 strands-grafana/provisioning/dashboards/health.json create mode 100644 strands-grafana/provisioning/dashboards/triage.json create mode 100644 strands-grafana/provisioning/datasources/automatic.yaml create mode 100644 strands-grafana/strands-metrics/Cargo.toml create mode 100644 strands-grafana/strands-metrics/src/aggregates.rs create mode 100644 strands-grafana/strands-metrics/src/client.rs create mode 100644 strands-grafana/strands-metrics/src/db.rs create mode 100644 strands-grafana/strands-metrics/src/main.rs diff --git a/strands-grafana/.gitignore b/strands-grafana/.gitignore new file mode 100644 index 0000000..6c0c18d --- /dev/null +++ b/strands-grafana/.gitignore @@ -0,0 +1,5 @@ +# SQLite database with metrics data (generated by strands-metrics) +metrics.db + +# Rust build artifacts +strands-metrics/target/ diff --git a/strands-grafana/README.md b/strands-grafana/README.md new file mode 100644 index 0000000..5798e0e --- /dev/null +++ b/strands-grafana/README.md @@ -0,0 +1,87 @@ +# strands-grafana + +GitHub metrics collection and Grafana dashboards for the [strands-agents](https://github.com/strands-agents) organization. + +This tool syncs GitHub data (issues, PRs, stars, commits, CI runs, etc.) into a local SQLite database, then visualizes it through pre-built Grafana dashboards. It provides org-wide health metrics including time-to-first-response, merge times, open item counts, star growth, and more. + +> Originally created by [@chaynabors](https://github.com/chaynabors) — migrated from [chaynabors/strands](https://github.com/chaynabors/strands) (commit `0fbe13c`). + +## Directory Structure + +``` +strands-grafana/ +├── README.md ← you are here +├── docker-compose.yaml ← Grafana container config +├── provisioning/ ← Grafana auto-provisioning +│ ├── datasources/ +│ │ └── automatic.yaml ← SQLite datasource config +│ └── dashboards/ +│ ├── dashboards.yaml ← dashboard provider config +│ ├── health.json ← org health dashboard +│ └── triage.json ← triage dashboard +└── strands-metrics/ ← Rust CLI for syncing GitHub data + ├── Cargo.toml + └── src/ + ├── main.rs + ├── client.rs + ├── db.rs + └── aggregates.rs +``` + +## Prerequisites + +- **Rust toolchain** — install via [rustup](https://rustup.rs/) +- **Docker** and **Docker Compose** — for running Grafana +- **GitHub personal access token** — with read access to the `strands-agents` org (public repos) + +## Usage + +### 1. Sync GitHub metrics + +From the `strands-grafana` directory: + +```bash +cd strands-metrics +GITHUB_TOKEN=ghp_your_token_here cargo run --release -- sync +``` + +This will: +- Fetch all public repos in the `strands-agents` org +- Sync issues, PRs, reviews, comments, stars, commits, and CI workflow runs +- Compute daily aggregate metrics +- Write everything to `../metrics.db` (i.e. `strands-grafana/metrics.db`) + +Subsequent runs are incremental — only new/updated data is fetched. + +#### Other commands + +```bash +# Sweep: reconcile locally-open items against GitHub (mark deleted/closed items) +GITHUB_TOKEN=ghp_xxx cargo run --release -- sweep + +# Query: run arbitrary SQL against the database +cargo run --release -- query "SELECT date, stars FROM daily_metrics WHERE repo = 'sdk-python' ORDER BY date DESC LIMIT 10" +``` + +### 2. Launch Grafana + +From the `strands-grafana` directory: + +```bash +docker-compose up +``` + +Then open [http://localhost:3000](http://localhost:3000) in your browser. + +Grafana is configured for anonymous read-only access — no login required. The SQLite database is mounted read-only into the container. + +### 3. Dashboards + +- **Health** — org-wide metrics: stars, open issues/PRs, merge times, CI health, code churn, response times +- **Triage** — focused view for issue/PR triage workflows + +## Notes + +- `metrics.db` is gitignored — you must run the sync yourself to populate it +- The sync respects GitHub API rate limits and will pause automatically when limits are low +- The default db path when running from `strands-metrics/` is `../metrics.db`, placing it in the `strands-grafana/` root where `docker-compose.yaml` expects it diff --git a/strands-grafana/docker-compose.yaml b/strands-grafana/docker-compose.yaml new file mode 100644 index 0000000..9b6dd03 --- /dev/null +++ b/strands-grafana/docker-compose.yaml @@ -0,0 +1,20 @@ +services: + grafana: + image: grafana/grafana:latest + container_name: grafana-sqlite-viz + user: "0:0" + ports: + - "3000:3000" + volumes: + - ./metrics.db:/var/lib/grafana/metrics.db:ro + - ./provisioning/datasources:/etc/grafana/provisioning/datasources + - ./provisioning/dashboards:/etc/grafana/provisioning/dashboards + environment: + - GF_INSTALL_PLUGINS=frser-sqlite-datasource + - GF_PLUGIN_FRSER_SQLITE_DATASOURCE_ALLOW_LOCAL_MODE=true + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer + - GF_AUTH_BASIC_ENABLED=false + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_USERS_ALLOW_SIGN_UP=false + restart: always diff --git a/strands-grafana/provisioning/dashboards/dashboards.yaml b/strands-grafana/provisioning/dashboards/dashboards.yaml new file mode 100644 index 0000000..0a19b11 --- /dev/null +++ b/strands-grafana/provisioning/dashboards/dashboards.yaml @@ -0,0 +1,11 @@ +apiVersion: 1 + +providers: + - name: "DevEx Dashboards" + orgId: 1 + folder: "" + type: file + disableDeletion: false + updateIntervalSeconds: 60 + options: + path: /etc/grafana/provisioning/dashboards diff --git a/strands-grafana/provisioning/dashboards/health.json b/strands-grafana/provisioning/dashboards/health.json new file mode 100644 index 0000000..1508b03 --- /dev/null +++ b/strands-grafana/provisioning/dashboards/health.json @@ -0,0 +1,12577 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 4, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 100, + "panels": [], + "title": "Volume", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_prs_count as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_prs_count as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Open PRs", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "Total count of open pull requests." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Open Issues", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "Total count of open issues (excluding pull requests)." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 23, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_opened as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_opened as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PRs Opened (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart", + "description": "Number of new pull requests opened per day." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 2, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Opened (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart", + "description": "Number of new issues opened per day." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "id": 1, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PRs Merged (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart", + "description": "Number of pull requests merged per day." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 3, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Closed (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart", + "description": "Number of issues closed per day." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": true, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_items_count - LAG(open_items_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_items_count - LAG(open_items_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Backlog Growth (Week-over-Week)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "Week-over-week change in total open items (issues + PRs). Positive = backlog growing, negative = backlog shrinking." + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 102, + "panels": [], + "title": "Quality", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "CI Failure Rate (7-Day Avg)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "7-day rolling average of CI failure rate: (failed CI runs / total CI runs) \u00d7 100%. Shows percentage of CI runs that failed." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent", + "min": 0, + "max": 100 + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN (${repo:singlequote})\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PR Acceptance Rate (30-Day Avg)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "30-day rolling average of PR acceptance rate: (PRs merged / PRs opened) \u00d7 100%. Shows what percentage of opened PRs ultimately get merged." + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 101, + "panels": [], + "title": "Speed", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 42 + }, + "id": 21, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND time_to_first_response > 0\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND time_to_first_response > 0\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Time to First Response", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "Average hours from issue/PR creation to first comment or review. 30-day rolling average." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 42 + }, + "id": 22, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND avg_issue_resolution_time > 0\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND avg_issue_resolution_time > 0\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issue Resolution Time", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "Average hours from issue creation to closure. 30-day rolling average." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 43 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Code Churn (7-Day Avg, <10k)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "7-day rolling average of total lines changed per day (additions + deletions). Filters out days with >10,000 line changes to exclude anomalies like generated code, large imports, or bulk formatting changes." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 50 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Cycle Time (PR Open \u2192 Merge, 14-Day Avg)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "Average hours from PR creation to merge, split by internal vs external contributors. 14-day rolling average." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 50 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Time to First Review (14-Day Avg)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "Average hours from PR creation to first review. 14-day rolling average." + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 51 + }, + "id": 103, + "panels": [], + "title": "Community", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 52 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Stars", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "Cumulative count of GitHub stars across selected repositories, tracked over time." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 52 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "queryType": "table", + "rawQueryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Weekly Active External Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "Count of unique external contributors (non-team members: not OWNER/MEMBER/COLLABORATOR) who created PRs in the rolling 7-day window ending on each date." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "percent", + "min": 0, + "max": 100 + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 60 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "External Contribution Rate (30-Day Avg)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries", + "description": "30-day rolling average percentage of merged PRs that were authored by external contributors (non-team members)." + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 60 + }, + "id": 9, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PRs Closed Without Merging (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart", + "description": "Daily count of PRs closed without being merged (rejected PRs), split by Internal (team) vs External (community) contributors." + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [ + { + "allowCustomValue": false, + "current": { + "text": [ + "agent-builder", + "agent-sop", + "docs", + "sdk-python", + "sdk-typescript", + "tools" + ], + "value": [ + "agent-builder", + "agent-sop", + "docs", + "sdk-python", + "sdk-typescript", + "tools" + ] + }, + "definition": "SELECT DISTINCT repo FROM daily_metrics", + "description": "", + "includeAll": true, + "multi": true, + "name": "repo", + "options": [], + "query": "SELECT DISTINCT repo FROM daily_metrics", + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30d", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Strands Health", + "uid": "adj9pgt", + "version": 2 +} \ No newline at end of file diff --git a/strands-grafana/provisioning/dashboards/triage.json b/strands-grafana/provisioning/dashboards/triage.json new file mode 100644 index 0000000..24b8c76 --- /dev/null +++ b/strands-grafana/provisioning/dashboards/triage.json @@ -0,0 +1,676 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 0, + "links": [], + "panels": [ + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hideFrom.viz", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Status" + }, + "properties": [ + { + "id": "custom.width", + "value": 118 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Days Open" + }, + "properties": [ + { + "id": "custom.width", + "value": 87 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Author" + }, + "properties": [ + { + "id": "custom.width", + "value": 148 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Repo" + }, + "properties": [ + { + "id": "custom.width", + "value": 161 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 22, + "x": 1, + "y": 0 + }, + "id": 1, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Days Open" + } + ] + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "queryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n CASE \n WHEN r.state = 'APPROVED' THEN 'Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN 'Changes Requested' \n ELSE 'Needs Review' \n END as \"Status\", \n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\" \nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \nORDER BY \"Days Open\" DESC", + "queryType": "table", + "rawQueryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n CASE \n WHEN r.state = 'APPROVED' THEN 'Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN 'Changes Requested' \n ELSE 'Needs Review' \n END as \"Status\", \n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\" \nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN (${repo:singlequote}) \nORDER BY \"Days Open\" DESC", + "refId": "A", + "timeColumns": ["time", "ts"] + } + ], + "title": "Team PRs", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hideFrom.viz", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Status" + }, + "properties": [ + { + "id": "custom.width", + "value": 118 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Days Open" + }, + "properties": [ + { + "id": "custom.width", + "value": 87 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Author" + }, + "properties": [ + { + "id": "custom.width", + "value": 148 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Repo" + }, + "properties": [ + { + "id": "custom.width", + "value": 161 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 22, + "x": 1, + "y": 8 + }, + "id": 2, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Days Open" + } + ] + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n CASE \n WHEN r.state = 'APPROVED' THEN 'Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN 'Changes Requested' \n ELSE 'Needs Review' \n END as \"Status\", \n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\" \nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN (${repo:singlequote}) \nORDER BY \"Days Open\" DESC", + "queryType": "table", + "rawQueryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n CASE \n WHEN r.state = 'APPROVED' THEN 'Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN 'Changes Requested' \n ELSE 'Needs Review' \n END as \"Status\", \n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\" \nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN (${repo:singlequote}) \nORDER BY \"Days Open\" DESC", + "refId": "A" + } + ], + "title": "Community PRs (External)", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hideFrom.viz", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Comments" + }, + "properties": [ + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Repo" + }, + "properties": [ + { + "id": "custom.width", + "value": 160 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 22, + "x": 1, + "y": 16 + }, + "id": 3, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Comments" + } + ] + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n repo as \"Repo\", \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.comments') as \"Comments\" \nFROM issues \nWHERE state = 'open' AND json_extract(data, '$.milestone') IS NULL AND repo IN (${repo:singlequote}) \nORDER BY created_at ASC", + "queryType": "table", + "rawQueryText": "SELECT \n repo as \"Repo\", \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.comments') as \"Comments\" \nFROM issues \nWHERE state = 'open' AND json_extract(data, '$.milestone') IS NULL AND repo IN (${repo:singlequote}) \nORDER BY created_at ASC", + "refId": "A" + } + ], + "title": "Issues Needing Triage", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hideFrom.viz", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Upvotes" + }, + "properties": [ + { + "id": "custom.width", + "value": 80 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 1, + "y": 24 + }, + "id": 4, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Upvotes" + } + ] + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.reactions.\"+1\"') as \"Upvotes\" \nFROM issues WHERE state = 'open' AND repo IN (${repo:singlequote}) \nORDER BY \"Upvotes\" DESC LIMIT 20", + "queryType": "table", + "rawQueryText": "SELECT \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.reactions.\"+1\"') as \"Upvotes\" \nFROM issues WHERE state = 'open' AND repo IN (${repo:singlequote}) \nORDER BY \"Upvotes\" DESC LIMIT 20", + "refId": "A", + "timeColumns": ["time", "ts"] + } + ], + "title": "Top Upvoted Issues", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hideFrom.viz", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Comments" + }, + "properties": [ + { + "id": "custom.width", + "value": 80 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 10, + "x": 13, + "y": 24 + }, + "id": 5, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Comments" + } + ] + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.comments') as \"Comments\" \nFROM issues WHERE state = 'open' AND repo IN (${repo:singlequote}) \nORDER BY \"Comments\" DESC LIMIT 20", + "queryType": "table", + "rawQueryText": "SELECT \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.comments') as \"Comments\" \nFROM issues WHERE state = 'open' AND repo IN (${repo:singlequote}) \nORDER BY \"Comments\" DESC LIMIT 20", + "refId": "A" + } + ], + "title": "Most Discussed Issues", + "type": "table" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [ + { + "allowCustomValue": false, + "current": { + "text": ["All"], + "value": ["$__all"] + }, + "definition": "SELECT DISTINCT repo FROM daily_metrics", + "includeAll": true, + "multi": true, + "name": "repo", + "options": [], + "query": "SELECT DISTINCT repo FROM daily_metrics", + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30d", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Strands Triage", + "uid": "advqxqk", + "version": 4 +} diff --git a/strands-grafana/provisioning/datasources/automatic.yaml b/strands-grafana/provisioning/datasources/automatic.yaml new file mode 100644 index 0000000..6296167 --- /dev/null +++ b/strands-grafana/provisioning/datasources/automatic.yaml @@ -0,0 +1,10 @@ +apiVersion: 1 + +datasources: + - name: GitHub Metrics (SQLite) + type: frser-sqlite-datasource + access: proxy + isDefault: true + jsonData: + path: /var/lib/grafana/metrics.db + mode: ro diff --git a/strands-grafana/strands-metrics/Cargo.toml b/strands-grafana/strands-metrics/Cargo.toml new file mode 100644 index 0000000..fec7d1c --- /dev/null +++ b/strands-grafana/strands-metrics/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "strands-metrics" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0" +chrono = { version = "0.4", features = ["serde"] } +clap = { version = "4.5", features = ["derive"] } +http = "1.4.0" +indicatif = "0.18.3" +octocrab = "0.49" +rusqlite = { version = "0.38", features = ["bundled"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tokio = { version = "1", features = ["full"] } +tracing = "0.1" +tracing-subscriber = "0.3" diff --git a/strands-grafana/strands-metrics/src/aggregates.rs b/strands-grafana/strands-metrics/src/aggregates.rs new file mode 100644 index 0000000..edcb5cb --- /dev/null +++ b/strands-grafana/strands-metrics/src/aggregates.rs @@ -0,0 +1,215 @@ +use anyhow::Result; +use chrono::{DateTime, Duration, Utc}; +use rusqlite::{params, Connection}; + +pub fn compute_metrics(conn: &Connection) -> Result<()> { + // Smart detect of dirty window + let last_metric_date: Option = conn + .query_row("SELECT max(date) FROM daily_metrics", [], |row| row.get(0)) + .ok(); + + let start_date = match last_metric_date { + Some(d) => DateTime::parse_from_str(&d, "%Y-%m-%d") + .map(|dt| dt.with_timezone(&Utc) - Duration::days(3)) + .unwrap_or_else(|_| Utc::now()), + None => DateTime::parse_from_rfc3339("2010-01-01T00:00:00Z") + .unwrap() + .with_timezone(&Utc), + }; + + let start_date_str = start_date.format("%Y-%m-%d").to_string(); + + // Clear out the dirty window so we can recompute + conn.execute( + "DELETE FROM daily_metrics WHERE date >= ?1", + params![start_date_str], + )?; + + // PERFORMANCE OPTIMIZATION: Calculate response times ONCE in a temp table + // Calculating this inside the daily loop was O(N^2) and incredibly slow. + conn.execute( + "CREATE TEMP TABLE IF NOT EXISTS temp_response_times AS + SELECT + parent.repo, + date(parent.created_at) as created_date, + (julianday(MIN(activity.activity_at)) - julianday(parent.created_at)) * 24 as hours_to_response + FROM ( + SELECT id, repo, number, author, created_at FROM issues + UNION ALL + SELECT id, repo, number, author, created_at FROM pull_requests + ) as parent + JOIN ( + SELECT repo, issue_number as ref_number, author, created_at as activity_at FROM issue_comments + UNION ALL + SELECT repo, pr_number as ref_number, author, submitted_at as activity_at FROM pr_reviews + UNION ALL + SELECT repo, pr_number as ref_number, author, created_at as activity_at FROM pr_review_comments + ) as activity + ON parent.repo = activity.repo + AND parent.number = activity.ref_number + AND activity.activity_at > parent.created_at + AND activity.author != parent.author + GROUP BY parent.repo, parent.number", + [], + )?; + + let now = Utc::now(); + let num_days = (now - start_date).num_days(); + + for i in 0..=num_days { + let date = start_date + Duration::days(i); + let date_str = date.format("%Y-%m-%d").to_string(); + + conn.execute( + "INSERT OR IGNORE INTO daily_metrics (date, repo) + SELECT DISTINCT ?1, repo FROM ( + SELECT repo FROM pull_requests + UNION SELECT repo FROM issues + UNION SELECT repo FROM stargazers + UNION SELECT repo FROM commits + )", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET prs_opened = (SELECT count(*) FROM pull_requests WHERE repo = daily_metrics.repo AND date(created_at) = date(daily_metrics.date)), + prs_merged = (SELECT count(*) FROM pull_requests WHERE repo = daily_metrics.repo AND merged_at IS NOT NULL AND date(merged_at) = date(daily_metrics.date)), + issues_opened = (SELECT count(*) FROM issues WHERE repo = daily_metrics.repo AND date(created_at) = date(daily_metrics.date)), + issues_closed = (SELECT count(*) FROM issues WHERE repo = daily_metrics.repo AND closed_at IS NOT NULL AND date(closed_at) = date(daily_metrics.date)) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET churn_additions = (SELECT COALESCE(SUM(additions), 0) FROM commits WHERE repo = daily_metrics.repo AND date(date) = date(daily_metrics.date)), + churn_deletions = (SELECT COALESCE(SUM(deletions), 0) FROM commits WHERE repo = daily_metrics.repo AND date(date) = date(daily_metrics.date)) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET ci_failures = (SELECT count(*) FROM workflow_runs WHERE repo = daily_metrics.repo AND conclusion = 'failure' AND date(created_at) = date(daily_metrics.date)), + ci_runs = (SELECT count(*) FROM workflow_runs WHERE repo = daily_metrics.repo AND date(created_at) = date(daily_metrics.date)) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET stars = ( + SELECT count(*) FROM stargazers + WHERE repo = daily_metrics.repo AND date(starred_at) <= date(daily_metrics.date) + ) + WHERE date = ?1", + params![date_str], + )?; + + // Open items snapshot (combined issues + PRs for backward compatibility) + conn.execute( + "UPDATE daily_metrics + SET open_items_count = ( + (SELECT count(*) FROM issues WHERE repo = daily_metrics.repo AND date(created_at) <= date(daily_metrics.date) AND (closed_at IS NULL OR date(closed_at) > date(daily_metrics.date))) + + + (SELECT count(*) FROM pull_requests WHERE repo = daily_metrics.repo AND date(created_at) <= date(daily_metrics.date) AND (closed_at IS NULL OR date(closed_at) > date(daily_metrics.date))) + ) + WHERE date = ?1", + params![date_str] + )?; + + // Open issues count (just issues, no PRs) + conn.execute( + "UPDATE daily_metrics + SET open_issues_count = ( + SELECT count(*) FROM issues WHERE repo = daily_metrics.repo AND date(created_at) <= date(daily_metrics.date) AND (closed_at IS NULL OR date(closed_at) > date(daily_metrics.date)) + ) + WHERE date = ?1", + params![date_str] + )?; + + // Open PRs count + conn.execute( + "UPDATE daily_metrics + SET open_prs_count = ( + SELECT count(*) FROM pull_requests WHERE repo = daily_metrics.repo AND date(created_at) <= date(daily_metrics.date) AND (closed_at IS NULL OR date(closed_at) > date(daily_metrics.date)) + ) + WHERE date = ?1", + params![date_str] + )?; + + // Response time stats - Optimized to use Temp Table + conn.execute( + "UPDATE daily_metrics + SET time_to_first_response = ( + SELECT AVG(hours_to_response) + FROM temp_response_times + WHERE repo = daily_metrics.repo + AND created_date = date(daily_metrics.date) + ) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET avg_issue_resolution_time = ( + SELECT AVG((julianday(closed_at) - julianday(created_at)) * 24) + FROM issues + WHERE repo = daily_metrics.repo + AND closed_at IS NOT NULL + AND date(closed_at) = date(daily_metrics.date) + ) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET avg_pr_resolution_time = ( + SELECT AVG((julianday(COALESCE(merged_at, closed_at)) - julianday(created_at)) * 24) + FROM pull_requests + WHERE repo = daily_metrics.repo + AND (merged_at IS NOT NULL OR closed_at IS NOT NULL) + AND date(COALESCE(merged_at, closed_at)) = date(daily_metrics.date) + ) + WHERE date = ?1", + params![date_str], + )?; + + // Internal vs external merge times + conn.execute( + "UPDATE daily_metrics + SET time_to_merge_internal = ( + SELECT AVG((julianday(merged_at) - julianday(created_at)) * 24) + FROM pull_requests + WHERE repo = daily_metrics.repo + AND merged_at IS NOT NULL + AND date(merged_at) = date(daily_metrics.date) + AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') + ) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET time_to_merge_external = ( + SELECT AVG((julianday(merged_at) - julianday(created_at)) * 24) + FROM pull_requests + WHERE repo = daily_metrics.repo + AND merged_at IS NOT NULL + AND date(merged_at) = date(daily_metrics.date) + AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') + ) + WHERE date = ?1", + params![date_str], + )?; + } + + // Cleanup temp table + conn.execute("DROP TABLE IF EXISTS temp_response_times", [])?; + + Ok(()) +} diff --git a/strands-grafana/strands-metrics/src/client.rs b/strands-grafana/strands-metrics/src/client.rs new file mode 100644 index 0000000..fe39d58 --- /dev/null +++ b/strands-grafana/strands-metrics/src/client.rs @@ -0,0 +1,730 @@ +use anyhow::Result; +use chrono::{DateTime, Datelike, Utc}; +use http::header::ACCEPT; +use http::StatusCode; +use indicatif::ProgressBar; +use octocrab::{models, Octocrab, OctocrabBuilder}; +use rusqlite::{params, Connection}; +use serde::Deserialize; +use serde_json::Value; +use std::collections::HashSet; + +#[derive(Deserialize, Debug)] +struct SimpleUser { + login: String, +} + +#[derive(Deserialize, Debug)] +struct StarEntry { + starred_at: Option>, + user: Option, +} + +pub struct GitHubClient<'a> { + pub gh: Octocrab, + db: &'a mut Connection, + pb: ProgressBar, +} + +impl<'a> GitHubClient<'a> { + pub fn new(gh: Octocrab, db: &'a mut Connection, pb: ProgressBar) -> Self { + Self { gh, db, pb } + } + + pub async fn check_limits(&self) -> Result<()> { + let rate = self.gh.ratelimit().get().await?; + let core = rate.resources.core; + + if core.remaining < 50 { + let reset = core.reset; + let now = Utc::now().timestamp() as u64; + let wait_secs = reset.saturating_sub(now) + 10; + self.pb + .set_message(format!("Rate limit low. Sleeping {}s...", wait_secs)); + tokio::time::sleep(tokio::time::Duration::from_secs(wait_secs)).await; + } + Ok(()) + } + + pub async fn sync_org(&mut self, org: &str) -> Result<()> { + self.check_limits().await?; + let repos = self.fetch_repos(org).await?; + for repo in repos { + self.pb.set_message(format!("Syncing {}", repo.name)); + self.sync_repo(org, &repo).await?; + } + Ok(()) + } + + pub async fn sweep_org(&mut self, org: &str) -> Result<()> { + self.check_limits().await?; + let repos = self.fetch_repos(org).await?; + for repo in repos { + self.pb.set_message(format!("Sweeping {}", repo.name)); + self.sweep_repo(org, &repo).await?; + } + Ok(()) + } + + async fn fetch_repos(&self, org: &str) -> Result> { + let mut repos = Vec::new(); + let mut page = self.gh.orgs(org).list_repos().per_page(100).send().await?; + repos.extend(page.items); + while let Some(next) = page.next { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + repos.extend(page.items); + } + + repos.retain(|r| { + !r.archived.unwrap_or(false) + && !r.private.unwrap_or(false) + && !r.name.starts_with("private_") + }); + + Ok(repos) + } + + async fn sweep_repo(&self, org: &str, repo: &models::Repository) -> Result<()> { + let mut remote_open_numbers = HashSet::new(); + let route = format!("/repos/{}/{}/issues", org, repo.name); + let mut page: octocrab::Page = self + .gh + .get( + &route, + Some(&serde_json::json!({ + "state": "open", "per_page": 100 + })), + ) + .await?; + + loop { + let next_page = page.next.clone(); + for item in page.items { + if let Some(num) = item.get("number").and_then(|n| n.as_i64()) { + remote_open_numbers.insert(num); + } + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + + let mut stmt = self.db.prepare( + "SELECT number FROM issues WHERE repo = ?1 AND state = 'open' AND closed_at IS NULL AND deleted_at IS NULL" + )?; + let local_open_nums: Vec = stmt + .query_map(params![repo.name], |row| row.get(0))? + .collect::, _>>()?; + + let now = Utc::now().to_rfc3339(); + + for local_num in local_open_nums { + if !remote_open_numbers.contains(&local_num) { + self.check_limits().await?; + let issue_route = format!("/repos/{}/{}/issues/{}", org, repo.name, local_num); + + let result: Result = self.gh.get(&issue_route, None::<&()>).await; + + match result { + Ok(json) => { + let state = json + .get("state") + .and_then(|s| s.as_str()) + .unwrap_or("closed"); + let closed_at = json.get("closed_at").and_then(|s| s.as_str()); + self.db.execute( + "UPDATE issues SET state = ?1, closed_at = ?2 WHERE repo = ?3 AND number = ?4", + params![state, closed_at, repo.name, local_num] + )?; + } + Err(e) => { + if Self::is_missing_resource(&e) { + // Explicit 404/410 means deleted/missing + self.db.execute( + "UPDATE issues SET state = 'deleted', deleted_at = ?1 WHERE repo = ?2 AND number = ?3", + params![now, repo.name, local_num] + )?; + } else { + // Any other error (500, 502, timeout) is a crash. + return Err(e.into()); + } + } + } + } + } + Ok(()) + } + + async fn sync_repo(&mut self, org: &str, repo: &models::Repository) -> Result<()> { + let repo_name = &repo.name; + let last_sync_key = format!("last_sync_{}_{}", org, repo_name); + + let since: DateTime = self + .db + .query_row( + "SELECT value FROM app_state WHERE key = ?1", + params![last_sync_key], + |row| { + let s: String = row.get(0)?; + Ok(DateTime::parse_from_rfc3339(&s) + .map(|dt| dt.with_timezone(&Utc)) + .unwrap_or(Utc::now())) + }, + ) + .unwrap_or_else(|_| { + DateTime::parse_from_rfc3339("1970-01-01T00:00:00Z") + .unwrap() + .with_timezone(&Utc) + }); + + self.sync_pull_requests(org, repo_name, since).await?; + self.sync_issues(org, repo_name, since).await?; + self.sync_issue_comments(org, repo_name, since).await?; + self.sync_pr_comments(org, repo_name, since).await?; + self.sync_stars(org, repo).await?; + self.sync_commits(org, repo_name, since).await?; + self.sync_workflows(org, repo_name, since).await?; + + let now_str = Utc::now().to_rfc3339(); + self.db.execute( + "INSERT OR REPLACE INTO app_state (key, value) VALUES (?1, ?2)", + params![last_sync_key, now_str], + )?; + + Ok(()) + } + + async fn sync_commits(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + + let route = format!("/repos/{}/{}/commits", org, repo); + let mut page: octocrab::Page = self + .gh + .get( + &route, + Some(&serde_json::json!({ + "since": since.to_rfc3339(), "per_page": 100 + })), + ) + .await?; + + loop { + let next_page = page.next.clone(); + + // Optimization: Collect SHAs and check in batch locally to avoid DB thrashing + let mut shas = HashSet::new(); + for item in &page.items { + if let Some(sha) = item.get("sha").and_then(|s| s.as_str()) { + shas.insert(sha.to_string()); + } + } + + for sha in shas { + // Check if exists + let exists: bool = self + .db + .query_row("SELECT 1 FROM commits WHERE sha = ?1", params![sha], |_| { + Ok(true) + }) + .unwrap_or(false); + + if !exists { + // We must fetch details to get stats (additions/deletions) + // Check limits BEFORE the heavy call + self.check_limits().await?; + + let detail_route = format!("/repos/{}/{}/commits/{}", org, repo, sha); + let detail: Value = self.gh.get(&detail_route, None::<&()>).await?; + + let author = detail + .get("commit") + .and_then(|c| c.get("author")) + .and_then(|a| a.get("name")) + .and_then(|n| n.as_str()) + .unwrap_or("unknown"); + + let date_str = detail + .get("commit") + .and_then(|c| c.get("author")) + .and_then(|a| a.get("date")) + .and_then(|d| d.as_str()) + .unwrap_or(""); + + let stats = detail.get("stats"); + let adds = stats + .and_then(|s| s.get("additions")) + .and_then(|v| v.as_i64()) + .unwrap_or(0); + let dels = stats + .and_then(|s| s.get("deletions")) + .and_then(|v| v.as_i64()) + .unwrap_or(0); + let msg = detail + .get("commit") + .and_then(|c| c.get("message")) + .and_then(|m| m.as_str()) + .unwrap_or(""); + + self.db.execute( + "INSERT OR REPLACE INTO commits (sha, repo, author, date, additions, deletions, message) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", + params![sha, repo, author, date_str, adds, dels, msg] + )?; + } + } + + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_workflows(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + let route = format!("/repos/{}/{}/actions/runs", org, repo); + let created_filter = format!(">{}", since.format("%Y-%m-%d")); + + let mut page: octocrab::Page = self + .gh + .get( + &route, + Some(&serde_json::json!({ + "created": created_filter, "per_page": 100 + })), + ) + .await?; + + loop { + let next_page = page.next.clone(); + for run in page.items { + let id = run.get("id").and_then(|v| v.as_i64()).unwrap_or(0); + let name = run.get("name").and_then(|v| v.as_str()).unwrap_or(""); + let head = run + .get("head_branch") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let conclusion = run + .get("conclusion") + .and_then(|v| v.as_str()) + .unwrap_or("in_progress"); + let created_at = run.get("created_at").and_then(|v| v.as_str()).unwrap_or(""); + let updated_at = run.get("updated_at").and_then(|v| v.as_str()).unwrap_or(""); + + let duration = if let (Some(start), Some(end)) = ( + run.get("created_at").and_then(|v| v.as_str()), + run.get("updated_at").and_then(|v| v.as_str()), + ) { + let s = DateTime::parse_from_rfc3339(start).unwrap_or(Utc::now().into()); + let e = DateTime::parse_from_rfc3339(end).unwrap_or(Utc::now().into()); + (e - s).num_milliseconds() + } else { + 0 + }; + + self.db.execute( + "INSERT OR REPLACE INTO workflow_runs (id, repo, name, head_branch, conclusion, created_at, updated_at, duration_ms) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)", + params![id, repo, name, head, conclusion, created_at, updated_at, duration] + )?; + } + + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_stars(&mut self, org: &str, repo: &models::Repository) -> Result<()> { + self.check_limits().await?; + let token = std::env::var("GITHUB_TOKEN").unwrap_or_default(); + let star_gh = OctocrabBuilder::new() + .personal_token(token) + .add_header(ACCEPT, "application/vnd.github.star+json".to_string()) + .build()?; + + let mut remote_users = HashSet::new(); + + let route = format!("/repos/{}/{}/stargazers", org, repo.name); + let mut page: octocrab::Page = star_gh + .get(&route, Some(&serde_json::json!({ "per_page": 100 }))) + .await?; + + loop { + let next_page = page.next.clone(); + for entry in page.items { + if let (Some(starred_at), Some(user)) = (entry.starred_at, entry.user) { + remote_users.insert(user.login.clone()); + self.db.execute( + "INSERT OR REPLACE INTO stargazers (repo, user, starred_at) VALUES (?1, ?2, ?3)", + params![repo.name, user.login, starred_at.to_rfc3339()], + )?; + } + } + if let Some(next) = next_page { + self.check_limits().await?; + page = star_gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + + let mut stmt = self + .db + .prepare("SELECT user FROM stargazers WHERE repo = ?1")?; + let rows = stmt.query_map(params![repo.name], |row| row.get::<_, String>(0))?; + + let mut to_delete = Vec::new(); + for local_user in rows { + let u = local_user?; + if !remote_users.contains(&u) { + to_delete.push(u); + } + } + + for u in to_delete { + self.db.execute( + "DELETE FROM stargazers WHERE repo = ?1 AND user = ?2", + params![repo.name, u], + )?; + } + + Ok(()) + } + + async fn sync_pull_requests(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + let mut page = self + .gh + .pulls(org, repo) + .list() + .state(octocrab::params::State::All) + .sort(octocrab::params::pulls::Sort::Updated) + .direction(octocrab::params::Direction::Descending) + .per_page(100) + .send() + .await?; + + let mut keep_fetching = true; + loop { + let next_page = page.next; + for pr in page.items { + if let Some(updated) = pr.updated_at { + if updated < since { + keep_fetching = false; + break; + } + } + + let json = serde_json::to_string(&pr)?; + let pr_id = pr.id.0 as i64; + let pr_number = pr.number as i64; + let state_str = match pr.state { + Some(models::IssueState::Open) => "open", + Some(models::IssueState::Closed) => "closed", + _ => "unknown", + }; + + self.db.execute( + "INSERT OR REPLACE INTO pull_requests + (id, repo, number, state, author, title, created_at, updated_at, merged_at, closed_at, data) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)", + params![ + pr_id, repo, pr_number, state_str, + pr.user.as_ref().map(|u| u.login.clone()).unwrap_or_default(), + pr.title.unwrap_or_default(), + pr.created_at.map(|d| d.to_rfc3339()).unwrap_or_default(), + pr.updated_at.map(|d| d.to_rfc3339()).unwrap_or_default(), + pr.merged_at.map(|t| t.to_rfc3339()), + pr.closed_at.map(|t| t.to_rfc3339()), + json + ], + )?; + + if pr.updated_at.map(|t| t >= since).unwrap_or(false) { + self.sync_reviews(org, repo, pr.number).await?; + } + } + + if !keep_fetching { + break; + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_reviews(&self, org: &str, repo: &str, pr_number: u64) -> Result<()> { + let mut page = self + .gh + .pulls(org, repo) + .list_reviews(pr_number) + .per_page(100) + .send() + .await?; + loop { + let next_page = page.next; + for review in page.items { + let json = serde_json::to_string(&review)?; + let review_id = review.id.0 as i64; + let pr_num = pr_number as i64; + let state_str = review + .state + .map(|s| format!("{:?}", s).to_uppercase()) + .unwrap_or_else(|| "UNKNOWN".to_string()); + + self.db.execute( + "INSERT OR REPLACE INTO pr_reviews (id, repo, pr_number, state, author, submitted_at, data) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", + params![ + review_id, repo, pr_num, state_str, + review.user.as_ref().map(|u| u.login.clone()).unwrap_or_default(), + review.submitted_at.map(|t| t.to_rfc3339()).unwrap_or_default(), + json + ], + )?; + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_issues(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + let route = format!("/repos/{}/{}/issues", org, repo); + + // GitHub's /issues endpoint rejects very old "since" dates (returns 0 items). + // This appears to work for our use case. + let use_since_filter = since.year() >= 2010; + + let mut page: octocrab::Page = if use_since_filter { + self.gh.get(&route, Some(&serde_json::json!({ + "state": "all", "sort": "updated", "direction": "desc", "since": since.to_rfc3339(), "per_page": 100 + }))).await? + } else { + // First sync: don't pass since parameter to avoid GitHub API bug + self.gh.get(&route, Some(&serde_json::json!({ + "state": "all", "sort": "updated", "direction": "desc", "per_page": 100 + }))).await? + }; + + let mut keep_fetching = true; + loop { + let next_page = page.next.clone(); + for issue in page.items { + let updated_at_str = issue + .get("updated_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let updated_at = DateTime::parse_from_rfc3339(updated_at_str) + .map(|dt| dt.with_timezone(&Utc)) + .unwrap_or_else(|_| Utc::now()); + + if updated_at < since { + keep_fetching = false; + break; + } + if issue.get("pull_request").is_some() { + continue; + } + + let json = serde_json::to_string(&issue)?; + let id = issue.get("id").and_then(|v| v.as_i64()).unwrap_or(0); + let number = issue.get("number").and_then(|v| v.as_i64()).unwrap_or(0); + let state = issue + .get("state") + .and_then(|v| v.as_str()) + .unwrap_or("unknown"); + let author = issue + .get("user") + .and_then(|u| u.get("login")) + .and_then(|l| l.as_str()) + .unwrap_or("unknown"); + let title = issue.get("title").and_then(|v| v.as_str()).unwrap_or(""); + let created = issue + .get("created_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let closed = issue.get("closed_at").and_then(|v| v.as_str()); + + self.db.execute( + "INSERT OR REPLACE INTO issues + (id, repo, number, state, author, title, created_at, updated_at, closed_at, data) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)", + params![id, repo, number, state, author, title, created, updated_at_str, closed, json], + )?; + } + if !keep_fetching { + break; + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_issue_comments(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + let route = format!("/repos/{}/{}/issues/comments", org, repo); + let mut page: octocrab::Page = self.gh.get(&route, Some(&serde_json::json!({ + "sort": "updated", "direction": "desc", "since": since.to_rfc3339(), "per_page": 100 + }))).await?; + + let mut keep_fetching = true; + loop { + let next_page = page.next.clone(); + for comment in page.items { + let updated_at_str = comment + .get("updated_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let updated_at = DateTime::parse_from_rfc3339(updated_at_str) + .map(|dt| dt.with_timezone(&Utc)) + .unwrap_or_else(|_| Utc::now()); + + if updated_at < since { + keep_fetching = false; + break; + } + let issue_url = comment + .get("issue_url") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let issue_number: i64 = issue_url + .split('/') + .next_back() + .unwrap_or("0") + .parse() + .unwrap_or(0); + let id = comment.get("id").and_then(|v| v.as_i64()).unwrap_or(0); + let author = comment + .get("user") + .and_then(|u| u.get("login")) + .and_then(|l| l.as_str()) + .unwrap_or("unknown"); + let created = comment + .get("created_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let json = serde_json::to_string(&comment)?; + + self.db.execute( + "INSERT OR REPLACE INTO issue_comments (id, repo, issue_number, author, created_at, updated_at, data) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", + params![id, repo, issue_number, author, created, updated_at_str, json], + )?; + } + if !keep_fetching { + break; + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_pr_comments(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + let route = format!("/repos/{}/{}/pulls/comments", org, repo); + let mut page: octocrab::Page = self.gh.get(&route, Some(&serde_json::json!({ + "sort": "updated", "direction": "desc", "since": since.to_rfc3339(), "per_page": 100 + }))).await?; + + let mut keep_fetching = true; + loop { + let next_page = page.next.clone(); + for comment in page.items { + let updated_at_str = comment + .get("updated_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let updated_at = DateTime::parse_from_rfc3339(updated_at_str) + .map(|dt| dt.with_timezone(&Utc)) + .unwrap_or_else(|_| Utc::now()); + + if updated_at < since { + keep_fetching = false; + break; + } + let pull_url = comment + .get("pull_request_url") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let pr_number: i64 = pull_url + .split('/') + .next_back() + .unwrap_or("0") + .parse() + .unwrap_or(0); + let id = comment.get("id").and_then(|v| v.as_i64()).unwrap_or(0); + let author = comment + .get("user") + .and_then(|u| u.get("login")) + .and_then(|l| l.as_str()) + .unwrap_or("unknown"); + let created = comment + .get("created_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let json = serde_json::to_string(&comment)?; + + self.db.execute( + "INSERT OR REPLACE INTO pr_review_comments (id, repo, pr_number, author, created_at, updated_at, data) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", + params![id, repo, pr_number, author, created, updated_at_str, json], + )?; + } + if !keep_fetching { + break; + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + fn is_missing_resource(err: &octocrab::Error) -> bool { + match err { + octocrab::Error::GitHub { source, .. } => { + source.status_code == StatusCode::NOT_FOUND + || source.status_code == StatusCode::GONE + || source.message.eq_ignore_ascii_case("Not Found") + || source.message.eq_ignore_ascii_case("Not Found.") + } + _ => false, + } + } +} diff --git a/strands-grafana/strands-metrics/src/db.rs b/strands-grafana/strands-metrics/src/db.rs new file mode 100644 index 0000000..294743b --- /dev/null +++ b/strands-grafana/strands-metrics/src/db.rs @@ -0,0 +1,192 @@ +use anyhow::Result; +use rusqlite::Connection; +use std::path::Path; + +pub fn init_db>(path: P) -> Result { + let conn = Connection::open(path)?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS app_state ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS pull_requests ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + number INTEGER NOT NULL, + state TEXT NOT NULL, + author TEXT NOT NULL, + title TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + merged_at TEXT, + closed_at TEXT, + deleted_at TEXT, + data TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS issues ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + number INTEGER NOT NULL, + state TEXT NOT NULL, + author TEXT NOT NULL, + title TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + closed_at TEXT, + deleted_at TEXT, + data TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS issue_comments ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + issue_number INTEGER NOT NULL, + author TEXT NOT NULL, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + data TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS pr_reviews ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + pr_number INTEGER NOT NULL, + state TEXT NOT NULL, + author TEXT NOT NULL, + submitted_at TEXT NOT NULL, + data TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS pr_review_comments ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + pr_number INTEGER NOT NULL, + author TEXT NOT NULL, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + data TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS stargazers ( + repo TEXT NOT NULL, + user TEXT NOT NULL, + starred_at TEXT NOT NULL, + PRIMARY KEY (repo, user) + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS commits ( + sha TEXT PRIMARY KEY, + repo TEXT NOT NULL, + author TEXT NOT NULL, + date TEXT NOT NULL, + additions INTEGER DEFAULT 0, + deletions INTEGER DEFAULT 0, + message TEXT + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS workflow_runs ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + name TEXT, + head_branch TEXT, + conclusion TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + duration_ms INTEGER DEFAULT 0 + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS daily_metrics ( + date TEXT NOT NULL, + repo TEXT NOT NULL, + + prs_opened INTEGER DEFAULT 0, + prs_merged INTEGER DEFAULT 0, + issues_opened INTEGER DEFAULT 0, + issues_closed INTEGER DEFAULT 0, + + churn_additions INTEGER DEFAULT 0, + churn_deletions INTEGER DEFAULT 0, + + ci_failures INTEGER DEFAULT 0, + ci_runs INTEGER DEFAULT 0, + + stars INTEGER DEFAULT 0, + + open_items_count INTEGER DEFAULT 0, + open_issues_count INTEGER DEFAULT 0, + open_prs_count INTEGER DEFAULT 0, + + time_to_first_response REAL DEFAULT 0, + avg_issue_resolution_time REAL DEFAULT 0, + avg_pr_resolution_time REAL DEFAULT 0, + + time_to_merge_internal REAL DEFAULT 0, + time_to_merge_external REAL DEFAULT 0, + + PRIMARY KEY (date, repo) + )", + [], + )?; + + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_pr_repo_updated ON pull_requests(repo, updated_at)", + [], + )?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_issues_repo_updated ON issues(repo, updated_at)", + [], + )?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_comments_repo_issue ON issue_comments(repo, issue_number)", + [], + )?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_reviews_repo_pr ON pr_reviews(repo, pr_number)", + [], + )?; + conn.execute("CREATE INDEX IF NOT EXISTS idx_review_comments_repo_pr ON pr_review_comments(repo, pr_number)", [])?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_stars_repo_date ON stargazers(repo, starred_at)", + [], + )?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_commits_repo_date ON commits(repo, date)", + [], + )?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_workflows_repo_date ON workflow_runs(repo, created_at)", + [], + )?; + + Ok(conn) +} diff --git a/strands-grafana/strands-metrics/src/main.rs b/strands-grafana/strands-metrics/src/main.rs new file mode 100644 index 0000000..479079a --- /dev/null +++ b/strands-grafana/strands-metrics/src/main.rs @@ -0,0 +1,119 @@ +mod aggregates; +mod client; +mod db; + +use anyhow::Result; +use clap::{Parser, Subcommand}; +use client::GitHubClient; +use db::init_db; +use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use octocrab::OctocrabBuilder; +use std::path::PathBuf; +use std::sync::Arc; +use tracing::level_filters::LevelFilter; + +const ORG: &str = "strands-agents"; + +#[derive(Parser)] +#[clap(author, version, about)] +struct Cli { + #[clap(long, short, default_value = "../metrics.db")] + db_path: PathBuf, + #[clap(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Smart sync. Grabs only what is new. + Sync, + /// Garbage collection. Checks open items against reality and marks missing ones as deleted. + Sweep, + /// Run raw SQL. + Query { sql: String }, +} + +#[tokio::main] +async fn main() -> Result<()> { + tracing_subscriber::fmt() + .with_writer(std::io::stderr) + .with_max_level(LevelFilter::WARN) + .init(); + + let args = Cli::parse(); + let mut conn = init_db(&args.db_path)?; + + match args.command { + Commands::Sync => { + let gh_token = std::env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN must be set"); + let octocrab = OctocrabBuilder::new().personal_token(gh_token).build()?; + + let m = Arc::new(MultiProgress::new()); + let sty = ProgressStyle::with_template("{spinner:.green} {msg}") + .unwrap() + .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ "); + + let pb = m.add(ProgressBar::new_spinner()); + pb.set_style(sty.clone()); + pb.enable_steady_tick(std::time::Duration::from_millis(120)); + pb.set_message("Initializing Sync..."); + + let mut client = GitHubClient::new(octocrab, &mut conn, pb.clone()); + + client.sync_org(ORG).await?; + + pb.set_message("Calculating metrics..."); + aggregates::compute_metrics(&conn)?; + + pb.finish_with_message("Done!"); + } + Commands::Sweep => { + let gh_token = std::env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN must be set"); + let octocrab = OctocrabBuilder::new().personal_token(gh_token).build()?; + + let m = Arc::new(MultiProgress::new()); + let sty = ProgressStyle::with_template("{spinner:.green} {msg}") + .unwrap() + .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ "); + + let pb = m.add(ProgressBar::new_spinner()); + pb.set_style(sty); + pb.enable_steady_tick(std::time::Duration::from_millis(120)); + pb.set_message("Starting Sweep..."); + + let mut client = GitHubClient::new(octocrab, &mut conn, pb.clone()); + client.sweep_org(ORG).await?; + + pb.finish_with_message("Sweep complete."); + } + Commands::Query { sql } => { + let mut stmt = conn.prepare(&sql)?; + let column_count = stmt.column_count(); + let names: Vec = stmt.column_names().into_iter().map(String::from).collect(); + + println!("{}", names.join(" | ")); + println!("{}", "-".repeat(names.len() * 15)); + + let mut rows = stmt.query([])?; + while let Some(row) = rows.next()? { + let mut row_values = Vec::new(); + for i in 0..column_count { + let val = row.get_ref(i)?; + let text = match val { + rusqlite::types::ValueRef::Null => "NULL".to_string(), + rusqlite::types::ValueRef::Integer(i) => i.to_string(), + rusqlite::types::ValueRef::Real(f) => f.to_string(), + rusqlite::types::ValueRef::Text(t) => { + String::from_utf8_lossy(t).to_string() + } + rusqlite::types::ValueRef::Blob(_) => "".to_string(), + }; + row_values.push(text); + } + println!("{}", row_values.join(" | ")); + } + } + } + + Ok(()) +} From b2297e77f110c1d6a2afd8584f1302400ff4501b Mon Sep 17 00:00:00 2001 From: Containerized Agent Date: Fri, 13 Feb 2026 22:13:17 +0000 Subject: [PATCH 02/22] feat: add unified Docker image and CDK deployment for strands-grafana - Add multi-stage Dockerfile: builds strands-metrics Rust binary, then assembles a single Grafana image with the binary, supercronic, and provisioning configs baked in. - Add entrypoint.sh: runs initial backfill if metrics.db is missing, sets up daily cron sync at 06:00 UTC via supercronic, then execs into Grafana's /run.sh. - Add docker/docker-compose.local.yaml for local development. - Add CDK stack (cdk/) deploying to us-west-2 with: - VPC (2 AZs, 1 NAT gateway) - EFS for persistent metrics.db storage (RETAIN policy) - ECS Fargate service (0.5 vCPU, 1 GB) - ALB on port 80 with /api/health checks - GitHub PAT injected from Secrets Manager - Update datasource path to /var/lib/grafana/data/metrics.db - Remove old root docker-compose.yaml (replaced by docker/ setup) - Rewrite README with local dev + AWS deployment instructions --- strands-grafana/.gitignore | 9 + strands-grafana/README.md | 139 ++++++++----- strands-grafana/cdk/.env.example | 3 + strands-grafana/cdk/bin/app.ts | 24 +++ strands-grafana/cdk/cdk.json | 26 +++ .../cdk/lib/strands-grafana-stack.ts | 187 ++++++++++++++++++ strands-grafana/cdk/package.json | 26 +++ strands-grafana/cdk/tsconfig.json | 25 +++ strands-grafana/docker-compose.yaml | 20 -- strands-grafana/docker/Dockerfile | 56 ++++++ .../docker/docker-compose.local.yaml | 21 ++ strands-grafana/docker/entrypoint.sh | 34 ++++ .../provisioning/datasources/automatic.yaml | 2 +- 13 files changed, 503 insertions(+), 69 deletions(-) create mode 100644 strands-grafana/cdk/.env.example create mode 100644 strands-grafana/cdk/bin/app.ts create mode 100644 strands-grafana/cdk/cdk.json create mode 100644 strands-grafana/cdk/lib/strands-grafana-stack.ts create mode 100644 strands-grafana/cdk/package.json create mode 100644 strands-grafana/cdk/tsconfig.json delete mode 100644 strands-grafana/docker-compose.yaml create mode 100644 strands-grafana/docker/Dockerfile create mode 100644 strands-grafana/docker/docker-compose.local.yaml create mode 100755 strands-grafana/docker/entrypoint.sh diff --git a/strands-grafana/.gitignore b/strands-grafana/.gitignore index 6c0c18d..b501a16 100644 --- a/strands-grafana/.gitignore +++ b/strands-grafana/.gitignore @@ -3,3 +3,12 @@ metrics.db # Rust build artifacts strands-metrics/target/ + +# CDK +cdk/node_modules/ +cdk/cdk.out/ +cdk/dist/ +cdk/.env + +# Docker local data +docker/data/ diff --git a/strands-grafana/README.md b/strands-grafana/README.md index 5798e0e..8fbdf73 100644 --- a/strands-grafana/README.md +++ b/strands-grafana/README.md @@ -2,86 +2,129 @@ GitHub metrics collection and Grafana dashboards for the [strands-agents](https://github.com/strands-agents) organization. -This tool syncs GitHub data (issues, PRs, stars, commits, CI runs, etc.) into a local SQLite database, then visualizes it through pre-built Grafana dashboards. It provides org-wide health metrics including time-to-first-response, merge times, open item counts, star growth, and more. +A unified Docker container syncs GitHub data (issues, PRs, stars, commits, CI runs, reviews, comments) into a local SQLite database on a daily cron schedule, and serves pre-built Grafana dashboards for org-wide health and triage visibility. -> Originally created by [@chaynabors](https://github.com/chaynabors) — migrated from [chaynabors/strands](https://github.com/chaynabors/strands) (commit `0fbe13c`). +> Originally created by [@chaynabors](https://github.com/chaynabors) — dashboards and metrics CLI migrated from [chaynabors/strands](https://github.com/chaynabors/strands) (commit `0fbe13c`). ## Directory Structure ``` strands-grafana/ -├── README.md ← you are here -├── docker-compose.yaml ← Grafana container config -├── provisioning/ ← Grafana auto-provisioning +├── README.md ← you are here +├── docker/ +│ ├── Dockerfile ← unified Grafana + metrics-sync image +│ ├── entrypoint.sh ← initial backfill, cron, then Grafana +│ └── docker-compose.local.yaml ← local dev compose +├── provisioning/ ← Grafana auto-provisioning │ ├── datasources/ -│ │ └── automatic.yaml ← SQLite datasource config +│ │ └── automatic.yaml ← SQLite datasource │ └── dashboards/ -│ ├── dashboards.yaml ← dashboard provider config -│ ├── health.json ← org health dashboard -│ └── triage.json ← triage dashboard -└── strands-metrics/ ← Rust CLI for syncing GitHub data - ├── Cargo.toml - └── src/ - ├── main.rs - ├── client.rs - ├── db.rs - └── aggregates.rs +│ ├── dashboards.yaml ← dashboard provider config +│ ├── health.json ← org health dashboard +│ └── triage.json ← triage dashboard +├── strands-metrics/ ← Rust CLI (syncs GitHub → SQLite) +│ ├── Cargo.toml +│ └── src/ +│ ├── main.rs +│ ├── client.rs +│ ├── db.rs +│ └── aggregates.rs +└── cdk/ ← AWS CDK deployment + ├── bin/app.ts + ├── lib/strands-grafana-stack.ts + ├── package.json + ├── tsconfig.json + ├── cdk.json + └── .env.example ``` ## Prerequisites -- **Rust toolchain** — install via [rustup](https://rustup.rs/) -- **Docker** and **Docker Compose** — for running Grafana -- **GitHub personal access token** — with read access to the `strands-agents` org (public repos) +| Tool | Purpose | +|------|---------| +| **Docker** + **Docker Compose** | Build & run the unified container | +| **GitHub PAT** | Token with read access to the `strands-agents` org (public repos) | +| **Node.js** ≥ 18 | CDK CLI (AWS deployment only) | +| **AWS CDK CLI** | `npm install -g aws-cdk` (AWS deployment only) | +| **Rust toolchain** | Only needed if building strands-metrics locally outside Docker | -## Usage +## Local Development -### 1. Sync GitHub metrics - -From the `strands-grafana` directory: +Build and run the unified container locally: ```bash -cd strands-metrics -GITHUB_TOKEN=ghp_your_token_here cargo run --release -- sync +cd strands-grafana +GITHUB_TOKEN=ghp_your_token docker compose -f docker/docker-compose.local.yaml up --build ``` -This will: -- Fetch all public repos in the `strands-agents` org -- Sync issues, PRs, reviews, comments, stars, commits, and CI workflow runs -- Compute daily aggregate metrics -- Write everything to `../metrics.db` (i.e. `strands-grafana/metrics.db`) +On first start the container will: +1. Run a full GitHub sync (this takes a few minutes) +2. Start a daily cron job (06:00 UTC) for incremental syncs +3. Launch Grafana + +Open [http://localhost:3000](http://localhost:3000) — no login required (anonymous read-only). -Subsequent runs are incremental — only new/updated data is fetched. +The SQLite database is persisted in `docker/data/` on the host so subsequent restarts skip the initial backfill. -#### Other commands +### Running strands-metrics standalone + +If you prefer to run the Rust CLI directly (without Docker): ```bash -# Sweep: reconcile locally-open items against GitHub (mark deleted/closed items) -GITHUB_TOKEN=ghp_xxx cargo run --release -- sweep +cd strands-metrics +GITHUB_TOKEN=ghp_xxx cargo run --release -- sync # full/incremental sync +GITHUB_TOKEN=ghp_xxx cargo run --release -- sweep # reconcile stale open items +cargo run --release -- query "SELECT date, stars FROM daily_metrics WHERE repo='sdk-python' ORDER BY date DESC LIMIT 10" +``` + +By default the CLI writes to `../metrics.db` (the `strands-grafana/` root). + +## AWS Deployment -# Query: run arbitrary SQL against the database -cargo run --release -- query "SELECT date, stars FROM daily_metrics WHERE repo = 'sdk-python' ORDER BY date DESC LIMIT 10" +The CDK stack deploys everything to AWS as a single Fargate service with EFS-backed persistent storage: + +``` +ALB (port 80) → ECS Fargate → unified Docker image → EFS (metrics.db) ``` -### 2. Launch Grafana +### 1. Create the GitHub token secret -From the `strands-grafana` directory: +```bash +aws secretsmanager create-secret \ + --name strands-grafana/github-token \ + --secret-string "ghp_your_token" \ + --region us-west-2 +``` + +### 2. Configure and deploy ```bash -docker-compose up +cd cdk +cp .env.example .env +# Edit .env — set GITHUB_SECRET_ARN to the ARN from step 1 + +npm install +npx cdk deploy ``` -Then open [http://localhost:3000](http://localhost:3000) in your browser. +The stack creates: +- **VPC** (2 AZs, 1 NAT gateway) +- **EFS** file system with access point at `/grafana-data` (RETAIN policy) +- **ECS Fargate** service (0.5 vCPU, 1 GB RAM) +- **ALB** on port 80 with health check at `/api/health` -Grafana is configured for anonymous read-only access — no login required. The SQLite database is mounted read-only into the container. +The ALB URL is printed in the stack outputs. -### 3. Dashboards +### Tear down -- **Health** — org-wide metrics: stars, open issues/PRs, merge times, CI health, code churn, response times -- **Triage** — focused view for issue/PR triage workflows +```bash +cd cdk +npx cdk destroy +``` -## Notes +> **Note:** The EFS file system has a RETAIN removal policy — delete it manually if you want to remove the data. -- `metrics.db` is gitignored — you must run the sync yourself to populate it -- The sync respects GitHub API rate limits and will pause automatically when limits are low -- The default db path when running from `strands-metrics/` is `../metrics.db`, placing it in the `strands-grafana/` root where `docker-compose.yaml` expects it +## Dashboards + +- **Health** — org-wide metrics: stars, open issues & PRs, merge times (internal vs external), CI health, code churn, time-to-first-response +- **Triage** — focused view for issue/PR triage workflows diff --git a/strands-grafana/cdk/.env.example b/strands-grafana/cdk/.env.example new file mode 100644 index 0000000..ee01d65 --- /dev/null +++ b/strands-grafana/cdk/.env.example @@ -0,0 +1,3 @@ +# ARN of the Secrets Manager secret holding the GitHub personal access token. +# The secret value should be a plain-text token (not JSON). +GITHUB_SECRET_ARN=arn:aws:secretsmanager:us-west-2:ACCOUNT:secret:strands-grafana/github-token diff --git a/strands-grafana/cdk/bin/app.ts b/strands-grafana/cdk/bin/app.ts new file mode 100644 index 0000000..9a1d2ee --- /dev/null +++ b/strands-grafana/cdk/bin/app.ts @@ -0,0 +1,24 @@ +#!/usr/bin/env node +import "source-map-support/register"; +import * as dotenv from "dotenv"; +import * as cdk from "aws-cdk-lib"; +import { StrandsGrafanaStack } from "../lib/strands-grafana-stack"; + +// Load environment variables from .env file (if present) +dotenv.config(); + +const app = new cdk.App(); + +const env = { + account: process.env.CDK_DEFAULT_ACCOUNT, + region: "us-west-2", +}; + +new StrandsGrafanaStack(app, "StrandsGrafanaStack", { + env, + description: + "Strands Grafana — GitHub metrics collection and dashboards for strands-agents org", + tags: { + Project: "strands-grafana", + }, +}); diff --git a/strands-grafana/cdk/cdk.json b/strands-grafana/cdk/cdk.json new file mode 100644 index 0000000..c820084 --- /dev/null +++ b/strands-grafana/cdk/cdk.json @@ -0,0 +1,26 @@ +{ + "app": "npx ts-node --prefer-ts-exts bin/app.ts", + "watch": { + "include": ["**"], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": ["aws"], + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/aws-iam:standardizedServicePrincipals": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": false + } +} diff --git a/strands-grafana/cdk/lib/strands-grafana-stack.ts b/strands-grafana/cdk/lib/strands-grafana-stack.ts new file mode 100644 index 0000000..ef9159f --- /dev/null +++ b/strands-grafana/cdk/lib/strands-grafana-stack.ts @@ -0,0 +1,187 @@ +import * as cdk from "aws-cdk-lib"; +import * as ec2 from "aws-cdk-lib/aws-ec2"; +import * as ecs from "aws-cdk-lib/aws-ecs"; +import * as efs from "aws-cdk-lib/aws-efs"; +import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2"; +import * as logs from "aws-cdk-lib/aws-logs"; +import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"; +import { Construct } from "constructs"; +import * as path from "path"; + +export class StrandsGrafanaStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + // ── Secrets Manager ────────────────────────────────────────────────── + // The GitHub PAT must already exist in Secrets Manager as a plain-text + // secret. Pass the ARN via the GITHUB_SECRET_ARN env var or CDK context. + const secretArn = + process.env.GITHUB_SECRET_ARN ?? + this.node.tryGetContext("githubSecretArn"); + + if (!secretArn) { + throw new Error( + "GITHUB_SECRET_ARN environment variable or 'githubSecretArn' CDK context must be set.\n" + + "Create the secret first:\n" + + ' aws secretsmanager create-secret --name strands-grafana/github-token --secret-string "ghp_xxx" --region us-west-2' + ); + } + + const githubSecret = secretsmanager.Secret.fromSecretCompleteArn( + this, + "GitHubTokenSecret", + secretArn + ); + + // ── VPC ────────────────────────────────────────────────────────────── + const vpc = new ec2.Vpc(this, "Vpc", { + maxAzs: 2, + natGateways: 1, + }); + + // ── EFS (persistent storage for metrics.db) ───────────────────────── + const fileSystem = new efs.FileSystem(this, "MetricsFs", { + vpc, + removalPolicy: cdk.RemovalPolicy.RETAIN, + performanceMode: efs.PerformanceMode.GENERAL_PURPOSE, + lifecyclePolicy: efs.LifecyclePolicy.AFTER_30_DAYS, + encrypted: true, + }); + + const accessPoint = fileSystem.addAccessPoint("GrafanaData", { + path: "/grafana-data", + createAcl: { + ownerUid: "0", + ownerGid: "0", + permissions: "755", + }, + posixUser: { + uid: "0", + gid: "0", + }, + }); + + // ── ECS Cluster ───────────────────────────────────────────────────── + const cluster = new ecs.Cluster(this, "Cluster", { + vpc, + containerInsights: true, + }); + + // ── Task Definition ───────────────────────────────────────────────── + const taskDef = new ecs.FargateTaskDefinition(this, "TaskDef", { + cpu: 512, + memoryLimitMiB: 1024, + }); + + // Mount EFS volume + taskDef.addVolume({ + name: "metrics-data", + efsVolumeConfiguration: { + fileSystemId: fileSystem.fileSystemId, + transitEncryption: "ENABLED", + authorizationConfig: { + accessPointId: accessPoint.accessPointId, + iam: "ENABLED", + }, + }, + }); + + // Grant EFS access to the task role + fileSystem.grant( + taskDef.taskRole, + "elasticfilesystem:ClientMount", + "elasticfilesystem:ClientWrite", + "elasticfilesystem:ClientRootAccess" + ); + + // Container definition — built from the unified Dockerfile + const container = taskDef.addContainer("grafana", { + image: ecs.ContainerImage.fromAsset( + path.join(__dirname, "../../"), + { + file: "docker/Dockerfile", + } + ), + logging: ecs.LogDrivers.awsLogs({ + streamPrefix: "strands-grafana", + logRetention: logs.RetentionDays.TWO_WEEKS, + }), + portMappings: [{ containerPort: 3000 }], + secrets: { + GITHUB_TOKEN: ecs.Secret.fromSecretsManager(githubSecret), + }, + healthCheck: { + command: [ + "CMD-SHELL", + "wget -qO- http://localhost:3000/api/health || exit 1", + ], + interval: cdk.Duration.seconds(30), + timeout: cdk.Duration.seconds(5), + retries: 3, + startPeriod: cdk.Duration.seconds(120), + }, + }); + + container.addMountPoints({ + sourceVolume: "metrics-data", + containerPath: "/var/lib/grafana/data", + readOnly: false, + }); + + // ── Fargate Service + ALB ─────────────────────────────────────────── + const service = new ecs.FargateService(this, "Service", { + cluster, + taskDefinition: taskDef, + desiredCount: 1, + assignPublicIp: false, + platformVersion: ecs.FargatePlatformVersion.LATEST, + }); + + // Allow the service to reach EFS + service.connections.allowTo(fileSystem, ec2.Port.tcp(2049), "EFS access"); + + // Application Load Balancer + const alb = new elbv2.ApplicationLoadBalancer(this, "Alb", { + vpc, + internetFacing: true, + }); + + const listener = alb.addListener("HttpListener", { + port: 80, + }); + + listener.addTargets("GrafanaTarget", { + port: 3000, + targets: [service], + healthCheck: { + path: "/api/health", + interval: cdk.Duration.seconds(30), + healthyThresholdCount: 2, + unhealthyThresholdCount: 3, + }, + deregistrationDelay: cdk.Duration.seconds(30), + }); + + // ── Outputs ───────────────────────────────────────────────────────── + new cdk.CfnOutput(this, "AlbUrl", { + value: `http://${alb.loadBalancerDnsName}`, + description: "Grafana dashboard URL (ALB)", + }); + + new cdk.CfnOutput(this, "EfsFileSystemId", { + value: fileSystem.fileSystemId, + description: "EFS file system ID (persistent metrics.db storage)", + }); + + new cdk.CfnOutput(this, "ClusterArn", { + value: cluster.clusterArn, + description: "ECS cluster ARN", + }); + + new cdk.CfnOutput(this, "CreateSecretCommand", { + value: + 'aws secretsmanager create-secret --name strands-grafana/github-token --secret-string "ghp_xxx" --region us-west-2', + description: "Command to create the GitHub token secret (one-time)", + }); + } +} diff --git a/strands-grafana/cdk/package.json b/strands-grafana/cdk/package.json new file mode 100644 index 0000000..a41c490 --- /dev/null +++ b/strands-grafana/cdk/package.json @@ -0,0 +1,26 @@ +{ + "name": "strands-grafana-cdk", + "version": "1.0.0", + "description": "AWS CDK infrastructure for Strands Grafana dashboards and metrics sync", + "bin": { + "cdk": "bin/app.js" + }, + "scripts": { + "build": "tsc", + "watch": "tsc -w", + "cdk": "cdk", + "synth": "cdk synth", + "deploy": "cdk deploy", + "destroy": "cdk destroy" + }, + "dependencies": { + "aws-cdk-lib": "^2.170.0", + "constructs": "^10.0.0", + "dotenv": "^16.0.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "aws-cdk": "^2.170.0", + "typescript": "^5.0.0" + } +} diff --git a/strands-grafana/cdk/tsconfig.json b/strands-grafana/cdk/tsconfig.json new file mode 100644 index 0000000..10368b0 --- /dev/null +++ b/strands-grafana/cdk/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "commonjs", + "lib": ["ES2022"], + "declaration": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": false, + "inlineSourceMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictPropertyInitialization": false, + "typeRoots": ["./node_modules/@types"], + "outDir": "dist", + "rootDir": "." + }, + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/strands-grafana/docker-compose.yaml b/strands-grafana/docker-compose.yaml deleted file mode 100644 index 9b6dd03..0000000 --- a/strands-grafana/docker-compose.yaml +++ /dev/null @@ -1,20 +0,0 @@ -services: - grafana: - image: grafana/grafana:latest - container_name: grafana-sqlite-viz - user: "0:0" - ports: - - "3000:3000" - volumes: - - ./metrics.db:/var/lib/grafana/metrics.db:ro - - ./provisioning/datasources:/etc/grafana/provisioning/datasources - - ./provisioning/dashboards:/etc/grafana/provisioning/dashboards - environment: - - GF_INSTALL_PLUGINS=frser-sqlite-datasource - - GF_PLUGIN_FRSER_SQLITE_DATASOURCE_ALLOW_LOCAL_MODE=true - - GF_AUTH_ANONYMOUS_ENABLED=true - - GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer - - GF_AUTH_BASIC_ENABLED=false - - GF_AUTH_DISABLE_LOGIN_FORM=true - - GF_USERS_ALLOW_SIGN_UP=false - restart: always diff --git a/strands-grafana/docker/Dockerfile b/strands-grafana/docker/Dockerfile new file mode 100644 index 0000000..210b975 --- /dev/null +++ b/strands-grafana/docker/Dockerfile @@ -0,0 +1,56 @@ +# ============================================================================= +# Stage 1: Build the strands-metrics Rust binary +# ============================================================================= +FROM rust:1.87-bookworm AS builder + +WORKDIR /build + +# Copy the Rust project source +COPY strands-metrics/Cargo.toml strands-metrics/Cargo.lock* ./ +COPY strands-metrics/src/ ./src/ + +# Build in release mode +RUN cargo build --release + +# ============================================================================= +# Stage 2: Unified Grafana + metrics sync image +# ============================================================================= +FROM grafana/grafana:latest + +USER root + +# Install ca-certificates and curl for downloading supercronic +RUN apk add --no-cache ca-certificates curl + +# Install supercronic (cron replacement designed for containers) +ARG SUPERCRONIC_VERSION=v0.2.43 +ARG SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/${SUPERCRONIC_VERSION}/supercronic-linux-amd64 +RUN curl -fsSL "${SUPERCRONIC_URL}" -o /usr/local/bin/supercronic \ + && chmod +x /usr/local/bin/supercronic + +# Copy the compiled strands-metrics binary +COPY --from=builder /build/target/release/strands-metrics /usr/local/bin/strands-metrics + +# Copy Grafana provisioning configs +COPY provisioning/datasources/ /etc/grafana/provisioning/datasources/ +COPY provisioning/dashboards/ /etc/grafana/provisioning/dashboards/ + +# Copy entrypoint script +COPY docker/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +# Create the data directory for EFS / local mount +RUN mkdir -p /var/lib/grafana/data + +# Grafana configuration via environment variables +ENV GF_INSTALL_PLUGINS=frser-sqlite-datasource +ENV GF_PLUGIN_FRSER_SQLITE_DATASOURCE_ALLOW_LOCAL_MODE=true +ENV GF_AUTH_ANONYMOUS_ENABLED=true +ENV GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer +ENV GF_AUTH_BASIC_ENABLED=false +ENV GF_AUTH_DISABLE_LOGIN_FORM=true +ENV GF_USERS_ALLOW_SIGN_UP=false + +EXPOSE 3000 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/strands-grafana/docker/docker-compose.local.yaml b/strands-grafana/docker/docker-compose.local.yaml new file mode 100644 index 0000000..e8adeb3 --- /dev/null +++ b/strands-grafana/docker/docker-compose.local.yaml @@ -0,0 +1,21 @@ +# Local development docker-compose +# Build and run the unified Grafana + metrics-sync container locally. +# +# Usage: +# GITHUB_TOKEN=ghp_xxx docker compose -f docker/docker-compose.local.yaml up --build +# +# Then open http://localhost:3000 + +services: + grafana: + build: + context: .. + dockerfile: docker/Dockerfile + container_name: strands-grafana + ports: + - "3000:3000" + volumes: + - ./data:/var/lib/grafana/data + environment: + - GITHUB_TOKEN=${GITHUB_TOKEN} + restart: unless-stopped diff --git a/strands-grafana/docker/entrypoint.sh b/strands-grafana/docker/entrypoint.sh new file mode 100755 index 0000000..fc641a9 --- /dev/null +++ b/strands-grafana/docker/entrypoint.sh @@ -0,0 +1,34 @@ +#!/bin/sh +set -e + +DB_PATH="/var/lib/grafana/data/metrics.db" + +# ── Initial backfill ──────────────────────────────────────────────────────── +# If the database doesn't exist yet, run a full sync before starting Grafana +# so the dashboards have data from the first boot. +if [ ! -f "$DB_PATH" ]; then + echo "[entrypoint] metrics.db not found — running initial sync..." + if [ -z "$GITHUB_TOKEN" ]; then + echo "[entrypoint] WARNING: GITHUB_TOKEN is not set. Skipping initial sync." + else + strands-metrics --db-path "$DB_PATH" sync || \ + echo "[entrypoint] WARNING: Initial sync failed (will retry on next cron run)." + fi +else + echo "[entrypoint] metrics.db already exists — skipping initial sync." +fi + +# ── Cron schedule ─────────────────────────────────────────────────────────── +# Sync daily at 06:00 UTC. Output is forwarded to container stdout/stderr +# via /proc/1/fd/1 so it shows up in docker logs / CloudWatch. +CRONTAB="/tmp/crontab" +cat > "$CRONTAB" <<'EOF' +0 6 * * * strands-metrics --db-path /var/lib/grafana/data/metrics.db sync >> /proc/1/fd/1 2>&1 +EOF + +echo "[entrypoint] Starting supercronic (daily sync at 06:00 UTC)..." +supercronic "$CRONTAB" & + +# ── Start Grafana ─────────────────────────────────────────────────────────── +echo "[entrypoint] Launching Grafana..." +exec /run.sh diff --git a/strands-grafana/provisioning/datasources/automatic.yaml b/strands-grafana/provisioning/datasources/automatic.yaml index 6296167..c3c6be5 100644 --- a/strands-grafana/provisioning/datasources/automatic.yaml +++ b/strands-grafana/provisioning/datasources/automatic.yaml @@ -6,5 +6,5 @@ datasources: access: proxy isDefault: true jsonData: - path: /var/lib/grafana/metrics.db + path: /var/lib/grafana/data/metrics.db mode: ro From 017c98f1012a0e8748eef1991ced2c2053a7c0f3 Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Fri, 13 Feb 2026 23:15:25 -0500 Subject: [PATCH 03/22] feat(strands-grafana): add CloudFront HTTPS, seed DB, and embedding support - Add CloudFront distribution for HTTPS access (*.cloudfront.net) - Bundle pre-built metrics.db as seed to avoid long first-boot backfill - Enable GF_SECURITY_ALLOW_EMBEDDING for iframe support - Make region configurable (CDK_DEFAULT_REGION / AWS_REGION / us-west-2) - Fix platform to LINUX_AMD64 for Fargate compatibility - Add .dockerignore to exclude cdk.out, node_modules, .git --- strands-grafana/.dockerignore | 3 ++ strands-grafana/README.md | 1 - strands-grafana/cdk/bin/app.ts | 2 +- .../cdk/lib/strands-grafana-stack.ts | 24 +++++++++++++- strands-grafana/docker/Dockerfile | 12 +++++-- strands-grafana/docker/entrypoint.sh | 33 ++++++++++++++----- 6 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 strands-grafana/.dockerignore diff --git a/strands-grafana/.dockerignore b/strands-grafana/.dockerignore new file mode 100644 index 0000000..c08d1f7 --- /dev/null +++ b/strands-grafana/.dockerignore @@ -0,0 +1,3 @@ +cdk/cdk.out +cdk/node_modules +.git diff --git a/strands-grafana/README.md b/strands-grafana/README.md index 8fbdf73..499202d 100644 --- a/strands-grafana/README.md +++ b/strands-grafana/README.md @@ -4,7 +4,6 @@ GitHub metrics collection and Grafana dashboards for the [strands-agents](https: A unified Docker container syncs GitHub data (issues, PRs, stars, commits, CI runs, reviews, comments) into a local SQLite database on a daily cron schedule, and serves pre-built Grafana dashboards for org-wide health and triage visibility. -> Originally created by [@chaynabors](https://github.com/chaynabors) — dashboards and metrics CLI migrated from [chaynabors/strands](https://github.com/chaynabors/strands) (commit `0fbe13c`). ## Directory Structure diff --git a/strands-grafana/cdk/bin/app.ts b/strands-grafana/cdk/bin/app.ts index 9a1d2ee..d61b931 100644 --- a/strands-grafana/cdk/bin/app.ts +++ b/strands-grafana/cdk/bin/app.ts @@ -11,7 +11,7 @@ const app = new cdk.App(); const env = { account: process.env.CDK_DEFAULT_ACCOUNT, - region: "us-west-2", + region: process.env.CDK_DEFAULT_REGION ?? process.env.AWS_REGION ?? "us-west-2", }; new StrandsGrafanaStack(app, "StrandsGrafanaStack", { diff --git a/strands-grafana/cdk/lib/strands-grafana-stack.ts b/strands-grafana/cdk/lib/strands-grafana-stack.ts index ef9159f..7126c57 100644 --- a/strands-grafana/cdk/lib/strands-grafana-stack.ts +++ b/strands-grafana/cdk/lib/strands-grafana-stack.ts @@ -3,6 +3,8 @@ import * as ec2 from "aws-cdk-lib/aws-ec2"; import * as ecs from "aws-cdk-lib/aws-ecs"; import * as efs from "aws-cdk-lib/aws-efs"; import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2"; +import * as cloudfront from "aws-cdk-lib/aws-cloudfront"; +import * as origins from "aws-cdk-lib/aws-cloudfront-origins"; import * as logs from "aws-cdk-lib/aws-logs"; import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"; import { Construct } from "constructs"; @@ -100,6 +102,7 @@ export class StrandsGrafanaStack extends cdk.Stack { path.join(__dirname, "../../"), { file: "docker/Dockerfile", + platform: cdk.aws_ecr_assets.Platform.LINUX_AMD64, } ), logging: ecs.LogDrivers.awsLogs({ @@ -152,6 +155,7 @@ export class StrandsGrafanaStack extends cdk.Stack { listener.addTargets("GrafanaTarget", { port: 3000, + protocol: elbv2.ApplicationProtocol.HTTP, targets: [service], healthCheck: { path: "/api/health", @@ -163,9 +167,27 @@ export class StrandsGrafanaStack extends cdk.Stack { }); // ── Outputs ───────────────────────────────────────────────────────── + // CloudFront distribution — provides HTTPS on *.cloudfront.net + const distribution = new cloudfront.Distribution(this, "Distribution", { + defaultBehavior: { + origin: new origins.HttpOrigin(alb.loadBalancerDnsName, { + protocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY, + }), + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED, + originRequestPolicy: cloudfront.OriginRequestPolicy.ALL_VIEWER, + allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL, + }, + }); + + new cdk.CfnOutput(this, "GrafanaUrl", { + value: `https://${distribution.distributionDomainName}`, + description: "Grafana dashboard URL (HTTPS via CloudFront)", + }); + new cdk.CfnOutput(this, "AlbUrl", { value: `http://${alb.loadBalancerDnsName}`, - description: "Grafana dashboard URL (ALB)", + description: "Grafana dashboard URL (ALB, HTTP only)", }); new cdk.CfnOutput(this, "EfsFileSystemId", { diff --git a/strands-grafana/docker/Dockerfile b/strands-grafana/docker/Dockerfile index 210b975..a1adb4a 100644 --- a/strands-grafana/docker/Dockerfile +++ b/strands-grafana/docker/Dockerfile @@ -1,7 +1,9 @@ # ============================================================================= # Stage 1: Build the strands-metrics Rust binary # ============================================================================= -FROM rust:1.87-bookworm AS builder +FROM rust:1.88-alpine AS builder + +RUN apk add --no-cache musl-dev pkgconfig openssl-dev openssl-libs-static WORKDIR /build @@ -9,7 +11,7 @@ WORKDIR /build COPY strands-metrics/Cargo.toml strands-metrics/Cargo.lock* ./ COPY strands-metrics/src/ ./src/ -# Build in release mode +# Build in release mode (statically linked against musl) RUN cargo build --release # ============================================================================= @@ -42,6 +44,11 @@ RUN chmod +x /entrypoint.sh # Create the data directory for EFS / local mount RUN mkdir -p /var/lib/grafana/data +# Bundle a pre-built metrics.db so the first boot doesn't need a long backfill. +# The entrypoint will copy this to the EFS volume if no DB exists yet. +# The wildcard pattern makes this a no-op if the file doesn't exist. +COPY docker/data/metrics.d[b] /seed/ + # Grafana configuration via environment variables ENV GF_INSTALL_PLUGINS=frser-sqlite-datasource ENV GF_PLUGIN_FRSER_SQLITE_DATASOURCE_ALLOW_LOCAL_MODE=true @@ -50,6 +57,7 @@ ENV GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer ENV GF_AUTH_BASIC_ENABLED=false ENV GF_AUTH_DISABLE_LOGIN_FORM=true ENV GF_USERS_ALLOW_SIGN_UP=false +ENV GF_SECURITY_ALLOW_EMBEDDING=true EXPOSE 3000 diff --git a/strands-grafana/docker/entrypoint.sh b/strands-grafana/docker/entrypoint.sh index fc641a9..dacd09c 100755 --- a/strands-grafana/docker/entrypoint.sh +++ b/strands-grafana/docker/entrypoint.sh @@ -4,18 +4,33 @@ set -e DB_PATH="/var/lib/grafana/data/metrics.db" # ── Initial backfill ──────────────────────────────────────────────────────── -# If the database doesn't exist yet, run a full sync before starting Grafana -# so the dashboards have data from the first boot. -if [ ! -f "$DB_PATH" ]; then - echo "[entrypoint] metrics.db not found — running initial sync..." - if [ -z "$GITHUB_TOKEN" ]; then - echo "[entrypoint] WARNING: GITHUB_TOKEN is not set. Skipping initial sync." +# If the database doesn't exist or is empty on the EFS volume, seed it from +# the pre-built copy baked into the image. The daily cron handles incremental +# updates from there — no hours-long backfill needed on first boot. +SEED_PATH="/seed/metrics.db" + +if [ ! -f "$DB_PATH" ] || [ ! -s "$DB_PATH" ]; then + if [ -f "$SEED_PATH" ]; then + echo "[entrypoint] Seeding metrics.db from bundled snapshot..." + cp "$SEED_PATH" "$DB_PATH" + echo "[entrypoint] Seed copy complete ($(du -h "$DB_PATH" | cut -f1))." + # Run a quick incremental sync to pick up anything newer than the snapshot + if [ -n "$GITHUB_TOKEN" ]; then + echo "[entrypoint] Running incremental sync to catch up..." + strands-metrics --db-path "$DB_PATH" sync || \ + echo "[entrypoint] WARNING: Incremental sync failed (will retry on next cron run)." + fi else - strands-metrics --db-path "$DB_PATH" sync || \ - echo "[entrypoint] WARNING: Initial sync failed (will retry on next cron run)." + echo "[entrypoint] No seed DB found — running full sync..." + if [ -z "$GITHUB_TOKEN" ]; then + echo "[entrypoint] WARNING: GITHUB_TOKEN is not set. Skipping sync." + else + strands-metrics --db-path "$DB_PATH" sync || \ + echo "[entrypoint] WARNING: Initial sync failed (will retry on next cron run)." + fi fi else - echo "[entrypoint] metrics.db already exists — skipping initial sync." + echo "[entrypoint] metrics.db already exists with data — skipping seed." fi # ── Cron schedule ─────────────────────────────────────────────────────────── From ff41c408be82f2d9ccf8a21001e416a99057f2f3 Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Fri, 13 Feb 2026 23:22:13 -0500 Subject: [PATCH 04/22] refactor: rename strands-grafana to community-dashboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename folder strands-grafana/ → community-dashboard/ - Rename CDK stack: StrandsGrafanaStack → CommunityDashboardStack - Rename stack file: strands-grafana-stack.ts → community-dashboard-stack.ts - Update all internal references (package.json, docker-compose, README, logs prefix) --- .../.dockerignore | 0 .../.gitignore | 0 .../README.md | 15 ++++++++------- .../cdk/.env.example | 0 .../cdk/bin/app.ts | 8 ++++---- .../cdk/cdk.json | 0 .../cdk/lib/community-dashboard-stack.ts | 4 ++-- .../cdk/package.json | 4 ++-- .../cdk/tsconfig.json | 0 .../docker/Dockerfile | 0 .../docker/docker-compose.local.yaml | 2 +- .../docker/entrypoint.sh | 0 .../provisioning/dashboards/dashboards.yaml | 0 .../provisioning/dashboards/health.json | 0 .../provisioning/dashboards/triage.json | 0 .../provisioning/datasources/automatic.yaml | 0 .../strands-metrics/Cargo.toml | 0 .../strands-metrics/src/aggregates.rs | 0 .../strands-metrics/src/client.rs | 0 .../strands-metrics/src/db.rs | 0 .../strands-metrics/src/main.rs | 0 21 files changed, 17 insertions(+), 16 deletions(-) rename {strands-grafana => community-dashboard}/.dockerignore (100%) rename {strands-grafana => community-dashboard}/.gitignore (100%) rename {strands-grafana => community-dashboard}/README.md (91%) rename {strands-grafana => community-dashboard}/cdk/.env.example (100%) rename {strands-grafana => community-dashboard}/cdk/bin/app.ts (60%) rename {strands-grafana => community-dashboard}/cdk/cdk.json (100%) rename strands-grafana/cdk/lib/strands-grafana-stack.ts => community-dashboard/cdk/lib/community-dashboard-stack.ts (98%) rename {strands-grafana => community-dashboard}/cdk/package.json (76%) rename {strands-grafana => community-dashboard}/cdk/tsconfig.json (100%) rename {strands-grafana => community-dashboard}/docker/Dockerfile (100%) rename {strands-grafana => community-dashboard}/docker/docker-compose.local.yaml (92%) rename {strands-grafana => community-dashboard}/docker/entrypoint.sh (100%) rename {strands-grafana => community-dashboard}/provisioning/dashboards/dashboards.yaml (100%) rename {strands-grafana => community-dashboard}/provisioning/dashboards/health.json (100%) rename {strands-grafana => community-dashboard}/provisioning/dashboards/triage.json (100%) rename {strands-grafana => community-dashboard}/provisioning/datasources/automatic.yaml (100%) rename {strands-grafana => community-dashboard}/strands-metrics/Cargo.toml (100%) rename {strands-grafana => community-dashboard}/strands-metrics/src/aggregates.rs (100%) rename {strands-grafana => community-dashboard}/strands-metrics/src/client.rs (100%) rename {strands-grafana => community-dashboard}/strands-metrics/src/db.rs (100%) rename {strands-grafana => community-dashboard}/strands-metrics/src/main.rs (100%) diff --git a/strands-grafana/.dockerignore b/community-dashboard/.dockerignore similarity index 100% rename from strands-grafana/.dockerignore rename to community-dashboard/.dockerignore diff --git a/strands-grafana/.gitignore b/community-dashboard/.gitignore similarity index 100% rename from strands-grafana/.gitignore rename to community-dashboard/.gitignore diff --git a/strands-grafana/README.md b/community-dashboard/README.md similarity index 91% rename from strands-grafana/README.md rename to community-dashboard/README.md index 499202d..ce1493f 100644 --- a/strands-grafana/README.md +++ b/community-dashboard/README.md @@ -1,4 +1,4 @@ -# strands-grafana +# community-dashboard GitHub metrics collection and Grafana dashboards for the [strands-agents](https://github.com/strands-agents) organization. @@ -8,7 +8,7 @@ A unified Docker container syncs GitHub data (issues, PRs, stars, commits, CI ru ## Directory Structure ``` -strands-grafana/ +community-dashboard/ ├── README.md ← you are here ├── docker/ │ ├── Dockerfile ← unified Grafana + metrics-sync image @@ -30,7 +30,7 @@ strands-grafana/ │ └── aggregates.rs └── cdk/ ← AWS CDK deployment ├── bin/app.ts - ├── lib/strands-grafana-stack.ts + ├── lib/community-dashboard-stack.ts ├── package.json ├── tsconfig.json ├── cdk.json @@ -52,7 +52,7 @@ strands-grafana/ Build and run the unified container locally: ```bash -cd strands-grafana +cd community-dashboard GITHUB_TOKEN=ghp_your_token docker compose -f docker/docker-compose.local.yaml up --build ``` @@ -76,14 +76,14 @@ GITHUB_TOKEN=ghp_xxx cargo run --release -- sweep # reconcile stale open it cargo run --release -- query "SELECT date, stars FROM daily_metrics WHERE repo='sdk-python' ORDER BY date DESC LIMIT 10" ``` -By default the CLI writes to `../metrics.db` (the `strands-grafana/` root). +By default the CLI writes to `../metrics.db` (the `community-dashboard/` root). ## AWS Deployment The CDK stack deploys everything to AWS as a single Fargate service with EFS-backed persistent storage: ``` -ALB (port 80) → ECS Fargate → unified Docker image → EFS (metrics.db) +CloudFront (HTTPS) → ALB (HTTP:80) → ECS Fargate → unified Docker image → EFS (metrics.db) ``` ### 1. Create the GitHub token secret @@ -111,8 +111,9 @@ The stack creates: - **EFS** file system with access point at `/grafana-data` (RETAIN policy) - **ECS Fargate** service (0.5 vCPU, 1 GB RAM) - **ALB** on port 80 with health check at `/api/health` +- **CloudFront** distribution for HTTPS access -The ALB URL is printed in the stack outputs. +The Grafana URL (HTTPS) is printed in the stack outputs. ### Tear down diff --git a/strands-grafana/cdk/.env.example b/community-dashboard/cdk/.env.example similarity index 100% rename from strands-grafana/cdk/.env.example rename to community-dashboard/cdk/.env.example diff --git a/strands-grafana/cdk/bin/app.ts b/community-dashboard/cdk/bin/app.ts similarity index 60% rename from strands-grafana/cdk/bin/app.ts rename to community-dashboard/cdk/bin/app.ts index d61b931..ef3cbcf 100644 --- a/strands-grafana/cdk/bin/app.ts +++ b/community-dashboard/cdk/bin/app.ts @@ -2,7 +2,7 @@ import "source-map-support/register"; import * as dotenv from "dotenv"; import * as cdk from "aws-cdk-lib"; -import { StrandsGrafanaStack } from "../lib/strands-grafana-stack"; +import { CommunityDashboardStack } from "../lib/community-dashboard-stack"; // Load environment variables from .env file (if present) dotenv.config(); @@ -14,11 +14,11 @@ const env = { region: process.env.CDK_DEFAULT_REGION ?? process.env.AWS_REGION ?? "us-west-2", }; -new StrandsGrafanaStack(app, "StrandsGrafanaStack", { +new CommunityDashboardStack(app, "CommunityDashboardStack", { env, description: - "Strands Grafana — GitHub metrics collection and dashboards for strands-agents org", + "Community Dashboard — GitHub metrics collection and dashboards for strands-agents org", tags: { - Project: "strands-grafana", + Project: "community-dashboard", }, }); diff --git a/strands-grafana/cdk/cdk.json b/community-dashboard/cdk/cdk.json similarity index 100% rename from strands-grafana/cdk/cdk.json rename to community-dashboard/cdk/cdk.json diff --git a/strands-grafana/cdk/lib/strands-grafana-stack.ts b/community-dashboard/cdk/lib/community-dashboard-stack.ts similarity index 98% rename from strands-grafana/cdk/lib/strands-grafana-stack.ts rename to community-dashboard/cdk/lib/community-dashboard-stack.ts index 7126c57..2d96771 100644 --- a/strands-grafana/cdk/lib/strands-grafana-stack.ts +++ b/community-dashboard/cdk/lib/community-dashboard-stack.ts @@ -10,7 +10,7 @@ import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"; import { Construct } from "constructs"; import * as path from "path"; -export class StrandsGrafanaStack extends cdk.Stack { +export class CommunityDashboardStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); @@ -106,7 +106,7 @@ export class StrandsGrafanaStack extends cdk.Stack { } ), logging: ecs.LogDrivers.awsLogs({ - streamPrefix: "strands-grafana", + streamPrefix: "community-dashboard", logRetention: logs.RetentionDays.TWO_WEEKS, }), portMappings: [{ containerPort: 3000 }], diff --git a/strands-grafana/cdk/package.json b/community-dashboard/cdk/package.json similarity index 76% rename from strands-grafana/cdk/package.json rename to community-dashboard/cdk/package.json index a41c490..4f8d12e 100644 --- a/strands-grafana/cdk/package.json +++ b/community-dashboard/cdk/package.json @@ -1,7 +1,7 @@ { - "name": "strands-grafana-cdk", + "name": "community-dashboard-cdk", "version": "1.0.0", - "description": "AWS CDK infrastructure for Strands Grafana dashboards and metrics sync", + "description": "AWS CDK infrastructure for community dashboard — GitHub metrics and Grafana", "bin": { "cdk": "bin/app.js" }, diff --git a/strands-grafana/cdk/tsconfig.json b/community-dashboard/cdk/tsconfig.json similarity index 100% rename from strands-grafana/cdk/tsconfig.json rename to community-dashboard/cdk/tsconfig.json diff --git a/strands-grafana/docker/Dockerfile b/community-dashboard/docker/Dockerfile similarity index 100% rename from strands-grafana/docker/Dockerfile rename to community-dashboard/docker/Dockerfile diff --git a/strands-grafana/docker/docker-compose.local.yaml b/community-dashboard/docker/docker-compose.local.yaml similarity index 92% rename from strands-grafana/docker/docker-compose.local.yaml rename to community-dashboard/docker/docker-compose.local.yaml index e8adeb3..0bc3f43 100644 --- a/strands-grafana/docker/docker-compose.local.yaml +++ b/community-dashboard/docker/docker-compose.local.yaml @@ -11,7 +11,7 @@ services: build: context: .. dockerfile: docker/Dockerfile - container_name: strands-grafana + container_name: community-dashboard ports: - "3000:3000" volumes: diff --git a/strands-grafana/docker/entrypoint.sh b/community-dashboard/docker/entrypoint.sh similarity index 100% rename from strands-grafana/docker/entrypoint.sh rename to community-dashboard/docker/entrypoint.sh diff --git a/strands-grafana/provisioning/dashboards/dashboards.yaml b/community-dashboard/provisioning/dashboards/dashboards.yaml similarity index 100% rename from strands-grafana/provisioning/dashboards/dashboards.yaml rename to community-dashboard/provisioning/dashboards/dashboards.yaml diff --git a/strands-grafana/provisioning/dashboards/health.json b/community-dashboard/provisioning/dashboards/health.json similarity index 100% rename from strands-grafana/provisioning/dashboards/health.json rename to community-dashboard/provisioning/dashboards/health.json diff --git a/strands-grafana/provisioning/dashboards/triage.json b/community-dashboard/provisioning/dashboards/triage.json similarity index 100% rename from strands-grafana/provisioning/dashboards/triage.json rename to community-dashboard/provisioning/dashboards/triage.json diff --git a/strands-grafana/provisioning/datasources/automatic.yaml b/community-dashboard/provisioning/datasources/automatic.yaml similarity index 100% rename from strands-grafana/provisioning/datasources/automatic.yaml rename to community-dashboard/provisioning/datasources/automatic.yaml diff --git a/strands-grafana/strands-metrics/Cargo.toml b/community-dashboard/strands-metrics/Cargo.toml similarity index 100% rename from strands-grafana/strands-metrics/Cargo.toml rename to community-dashboard/strands-metrics/Cargo.toml diff --git a/strands-grafana/strands-metrics/src/aggregates.rs b/community-dashboard/strands-metrics/src/aggregates.rs similarity index 100% rename from strands-grafana/strands-metrics/src/aggregates.rs rename to community-dashboard/strands-metrics/src/aggregates.rs diff --git a/strands-grafana/strands-metrics/src/client.rs b/community-dashboard/strands-metrics/src/client.rs similarity index 100% rename from strands-grafana/strands-metrics/src/client.rs rename to community-dashboard/strands-metrics/src/client.rs diff --git a/strands-grafana/strands-metrics/src/db.rs b/community-dashboard/strands-metrics/src/db.rs similarity index 100% rename from strands-grafana/strands-metrics/src/db.rs rename to community-dashboard/strands-metrics/src/db.rs diff --git a/strands-grafana/strands-metrics/src/main.rs b/community-dashboard/strands-metrics/src/main.rs similarity index 100% rename from strands-grafana/strands-metrics/src/main.rs rename to community-dashboard/strands-metrics/src/main.rs From 96490a1ec2ffd9ff9591e7d5ad524538fb352f32 Mon Sep 17 00:00:00 2001 From: Jonathan Segev Date: Sat, 14 Feb 2026 18:23:24 -0500 Subject: [PATCH 05/22] feat: Add community dashboard with metrics CLI, Grafana dashboards, and AWS deployment Add a comprehensive GitHub metrics dashboard for the strands-agents org: - Rust CLI (strands-metrics) that syncs GitHub data (PRs, issues, stars, commits, CI runs, reviews, comments) and PyPI/npm download stats into SQLite - 7 Grafana dashboards organized in 3 folders (General, SDKs, Operations): Executive Summary, Health, Python SDK, TypeScript SDK, Evaluations, Team Performance, and Triage - Configurable goal thresholds (goals.yaml) with warning levels - Team member tracking (team.yaml) for the Team Performance dashboard - Package download tracking (packages.yaml) from PyPI and npm registries - Docker setup with supercronic for daily automated sync - AWS CDK stack (Fargate + EFS + ALB + CloudFront) for production deployment - GitHub Actions workflow for daily metrics.db updates Supersedes #30 with additional dashboards, download tracking, goal configuration, team management, and dashboard folder organization. --- .github/workflows/community-dashboard.yaml | 67 + community-dashboard/.dockerignore | 4 + community-dashboard/.gitignore | 16 + community-dashboard/Cargo.toml | 20 + community-dashboard/README.md | 253 + community-dashboard/cdk/.env.example | 3 + community-dashboard/cdk/bin/app.ts | 24 + community-dashboard/cdk/cdk.json | 26 + .../cdk/lib/community-dashboard-stack.ts | 209 + community-dashboard/cdk/package.json | 26 + community-dashboard/cdk/tsconfig.json | 25 + community-dashboard/docker-compose.yaml | 21 + community-dashboard/docker/Dockerfile | 69 + .../docker/docker-compose.local.yaml | 21 + community-dashboard/docker/entrypoint.sh | 65 + community-dashboard/goals.yaml | 111 + community-dashboard/packages.yaml | 26 + .../provisioning/dashboards/dashboards.yaml | 29 + .../dashboards/general/executive.json | 1398 ++ .../dashboards/general/health.json | 12164 ++++++++++++++++ .../dashboards/operations/team.json | 641 + .../dashboards/operations/triage.json | 1214 ++ .../provisioning/dashboards/sdks/evals.json | 11853 +++++++++++++++ .../dashboards/sdks/python-sdk.json | 11855 +++++++++++++++ .../dashboards/sdks/typescript-sdk.json | 11853 +++++++++++++++ .../provisioning/datasources/automatic.yaml | 10 + community-dashboard/src/aggregates.rs | 215 + community-dashboard/src/client.rs | 730 + community-dashboard/src/db.rs | 210 + community-dashboard/src/downloads.rs | 287 + community-dashboard/src/goals.rs | 389 + community-dashboard/src/main.rs | 242 + community-dashboard/team.yaml | 20 + 33 files changed, 54096 insertions(+) create mode 100644 .github/workflows/community-dashboard.yaml create mode 100644 community-dashboard/.dockerignore create mode 100644 community-dashboard/.gitignore create mode 100644 community-dashboard/Cargo.toml create mode 100644 community-dashboard/README.md create mode 100644 community-dashboard/cdk/.env.example create mode 100644 community-dashboard/cdk/bin/app.ts create mode 100644 community-dashboard/cdk/cdk.json create mode 100644 community-dashboard/cdk/lib/community-dashboard-stack.ts create mode 100644 community-dashboard/cdk/package.json create mode 100644 community-dashboard/cdk/tsconfig.json create mode 100644 community-dashboard/docker-compose.yaml create mode 100644 community-dashboard/docker/Dockerfile create mode 100644 community-dashboard/docker/docker-compose.local.yaml create mode 100644 community-dashboard/docker/entrypoint.sh create mode 100644 community-dashboard/goals.yaml create mode 100644 community-dashboard/packages.yaml create mode 100644 community-dashboard/provisioning/dashboards/dashboards.yaml create mode 100644 community-dashboard/provisioning/dashboards/general/executive.json create mode 100644 community-dashboard/provisioning/dashboards/general/health.json create mode 100644 community-dashboard/provisioning/dashboards/operations/team.json create mode 100644 community-dashboard/provisioning/dashboards/operations/triage.json create mode 100644 community-dashboard/provisioning/dashboards/sdks/evals.json create mode 100644 community-dashboard/provisioning/dashboards/sdks/python-sdk.json create mode 100644 community-dashboard/provisioning/dashboards/sdks/typescript-sdk.json create mode 100644 community-dashboard/provisioning/datasources/automatic.yaml create mode 100644 community-dashboard/src/aggregates.rs create mode 100644 community-dashboard/src/client.rs create mode 100644 community-dashboard/src/db.rs create mode 100644 community-dashboard/src/downloads.rs create mode 100644 community-dashboard/src/goals.rs create mode 100644 community-dashboard/src/main.rs create mode 100644 community-dashboard/team.yaml diff --git a/.github/workflows/community-dashboard.yaml b/.github/workflows/community-dashboard.yaml new file mode 100644 index 0000000..cd0b292 --- /dev/null +++ b/.github/workflows/community-dashboard.yaml @@ -0,0 +1,67 @@ +name: Update Community Dashboard Metrics + +on: + schedule: + - cron: "0 6 * * *" # 6 AM UTC daily + workflow_dispatch: + +permissions: + contents: write + +defaults: + run: + working-directory: community-dashboard + +jobs: + update-metrics: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + lfs: true + + - name: Install Rust Toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Cache Cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + community-dashboard/target + key: ${{ runner.os }}-cargo-${{ hashFiles('community-dashboard/Cargo.toml') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Sync GitHub Data + env: + GITHUB_TOKEN: ${{ secrets.METRICS_PAT }} + RUST_LOG: info + run: cargo run --release -- sync + + - name: Garbage Collection (Sweep) + env: + GITHUB_TOKEN: ${{ secrets.METRICS_PAT }} + RUST_LOG: info + run: cargo run --release -- sweep + + - name: Sync Package Downloads (PyPI/npm) + env: + RUST_LOG: info + run: cargo run --release -- sync-downloads + + - name: Load Goals Configuration + run: cargo run --release -- load-goals goals.yaml + + - name: Load Team Configuration + run: cargo run --release -- load-team team.yaml + + - name: Commit and Push to Main + working-directory: . + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git add community-dashboard/metrics.db + git commit -m "chore: update community-dashboard metrics.db for $(date +'%Y-%m-%d')" || echo "No changes to commit" + git push origin main diff --git a/community-dashboard/.dockerignore b/community-dashboard/.dockerignore new file mode 100644 index 0000000..4f6e01c --- /dev/null +++ b/community-dashboard/.dockerignore @@ -0,0 +1,4 @@ +cdk/cdk.out +cdk/node_modules +target/ +.git diff --git a/community-dashboard/.gitignore b/community-dashboard/.gitignore new file mode 100644 index 0000000..e963587 --- /dev/null +++ b/community-dashboard/.gitignore @@ -0,0 +1,16 @@ +metrics.db +target/ +Cargo.lock + +# CDK +cdk/node_modules/ +cdk/cdk.out/ +cdk/dist/ +cdk/.env + +# Docker +docker/data/ + +# IDE +.idea/ +.DS_Store diff --git a/community-dashboard/Cargo.toml b/community-dashboard/Cargo.toml new file mode 100644 index 0000000..1e4f51b --- /dev/null +++ b/community-dashboard/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "strands-metrics" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0" +chrono = { version = "0.4", features = ["serde"] } +clap = { version = "4.5", features = ["derive"] } +http = "1.4.0" +indicatif = "0.18.3" +octocrab = "0.49" +rusqlite = { version = "0.38", features = ["bundled"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +serde_yaml = "0.9" +reqwest = { version = "0.12", features = ["json"] } +tokio = { version = "1", features = ["full"] } +tracing = "0.1" +tracing-subscriber = "0.3" diff --git a/community-dashboard/README.md b/community-dashboard/README.md new file mode 100644 index 0000000..1520a62 --- /dev/null +++ b/community-dashboard/README.md @@ -0,0 +1,253 @@ +# Community Dashboard + +GitHub metrics dashboards for the `strands-agents` organization. Collects data from GitHub, PyPI, and npm into a SQLite database, then visualizes it through pre-built Grafana dashboards. + +Deployable locally via Docker Compose or to AWS via CDK (Fargate + EFS + CloudFront). + +## Directory Structure + +``` +community-dashboard/ +├── Cargo.toml # Rust CLI project +├── src/ # strands-metrics CLI source +│ ├── main.rs # CLI entry point (sync, sweep, query, etc.) +│ ├── client.rs # GitHub API client (octocrab) +│ ├── db.rs # SQLite schema & initialization +│ ├── downloads.rs # PyPI/npm download tracking +│ ├── goals.rs # Goal thresholds & team management +│ └── aggregates.rs # Daily metric computation +├── goals.yaml # Configurable goal thresholds +├── team.yaml # Team members for performance tracking +├── packages.yaml # Package-to-registry mappings +├── docker-compose.yaml # Quick local Grafana (read-only) +├── docker/ +│ ├── Dockerfile # Unified Grafana + metrics-sync image +│ ├── docker-compose.local.yaml # Local dev with auto-sync +│ └── entrypoint.sh # Container startup script +├── provisioning/ +│ ├── datasources/ +│ │ └── automatic.yaml # SQLite datasource config +│ └── dashboards/ +│ ├── dashboards.yaml # Dashboard folder provider config +│ ├── general/ # Top-level dashboards +│ │ ├── executive.json # Executive Summary +│ │ └── health.json # Org Health +│ ├── sdks/ # SDK-specific dashboards +│ │ ├── evals.json # Evaluations +│ │ ├── python-sdk.json # Python SDK +│ │ └── typescript-sdk.json # TypeScript SDK +│ └── operations/ # Operations dashboards +│ ├── team.json # Team Performance +│ └── triage.json # Triage +└── cdk/ # AWS CDK deployment stack + ├── bin/app.ts + ├── lib/community-dashboard-stack.ts + ├── package.json + └── cdk.json +``` + +## Quick Start (Local) + +### Option A: Docker Compose with existing database + +If you already have a `metrics.db`, place it in this directory and run: + +```bash +docker compose up +``` + +Open [http://localhost:3000](http://localhost:3000). Grafana starts in anonymous viewer mode with all dashboards pre-loaded. + +### Option B: Docker with auto-sync + +Build the unified image that syncs GitHub data automatically: + +```bash +GITHUB_TOKEN=ghp_xxx docker compose -f docker/docker-compose.local.yaml up --build +``` + +This builds the Rust CLI, runs an initial sync on startup, and schedules daily updates at 06:00 UTC via supercronic. + +### Option C: Standalone CLI + +Build and run `strands-metrics` directly: + +```bash +# Build +cargo build --release + +# Sync GitHub data (PRs, issues, stars, commits, CI runs, reviews) +GITHUB_TOKEN=ghp_xxx cargo run --release -- sync + +# Garbage collection (reconcile stale open items) +GITHUB_TOKEN=ghp_xxx cargo run --release -- sweep + +# Sync PyPI/npm download stats +cargo run --release -- sync-downloads + +# Load goal thresholds into the database +cargo run --release -- load-goals goals.yaml + +# Load team members for the Team dashboard +cargo run --release -- load-team team.yaml + +# Backfill historical downloads (PyPI: ~180 days, npm: ~365 days) +cargo run --release -- backfill-downloads + +# Run arbitrary SQL queries +cargo run --release -- query "SELECT repo, SUM(prs_merged) FROM daily_metrics GROUP BY repo" +``` + +Then start Grafana to visualize: + +```bash +docker compose up +``` + +## CLI Commands + +| Command | Description | +|---------|-------------| +| `sync` | Incremental sync of GitHub data (PRs, issues, stars, commits, CI, reviews, comments) | +| `sweep` | Garbage collection -- checks open items against GitHub and marks missing ones as deleted | +| `query ` | Run raw SQL against the metrics database | +| `load-goals [path]` | Load goal thresholds from YAML into the database | +| `list-goals` | Display all configured goal thresholds | +| `load-team [path]` | Load team members from YAML (or `--members alice,bob`) | +| `sync-downloads` | Sync recent package downloads from PyPI and npm (default: 30 days) | +| `backfill-downloads` | Backfill historical download data (PyPI: ~180 days, npm: ~365 days) | + +### Global flags + +| Flag | Default | Description | +|------|---------|-------------| +| `--db-path` / `-d` | `metrics.db` | Path to the SQLite database file | + +## Dashboards + +### General + +- **Executive Summary** -- High-level org overview: total stars, open PRs/issues, stale PR count, contributor trends +- **Health** -- Org health metrics with goal lines: merge time, cycle time, CI failure rate, community PR %, contributor retention, response times + +### SDKs + +- **Python SDK** -- Python SDK-specific metrics: PRs, issues, stars, downloads from PyPI +- **TypeScript SDK** -- TypeScript SDK metrics with npm download tracking +- **Evaluations** -- Evals framework metrics + +### Operations + +- **Team Performance** -- Per-member activity tracking: PRs opened/merged, reviews given, issues closed +- **Triage** -- Open issues and PRs requiring attention, sorted by staleness + +## Configuration + +### goals.yaml + +Defines target thresholds that appear as goal lines on Health dashboard panels: + +```yaml +goals: + avg_merge_time_hours: + value: 24 + label: "Goal (24h)" + direction: lower_is_better # green below, red above + # warning_ratio: 0.75 # optional, default varies by direction +``` + +Each goal requires: +- `value` -- The target threshold +- `label` -- Display label for the goal line +- `direction` -- `lower_is_better` or `higher_is_better` +- `warning_ratio` -- (optional) Multiplier for warning threshold (default: 0.75 for lower, 0.70 for higher) + +### team.yaml + +Lists team members tracked in the Team Performance dashboard: + +```yaml +members: + - username: alice + - username: bob +``` + +### packages.yaml + +Maps GitHub repos to their published packages for download tracking: + +```yaml +repo_mappings: + sdk-python: + - package: strands-agents + registry: pypi + sdk-typescript: + - package: "@strands-agents/sdk" + registry: npm +``` + +## AWS Deployment (CDK) + +### Prerequisites + +1. AWS CLI configured with appropriate credentials +2. Node.js 18+ +3. A GitHub PAT stored in AWS Secrets Manager: + ```bash + aws secretsmanager create-secret \ + --name strands-grafana/github-token \ + --secret-string "ghp_xxx" \ + --region us-west-2 + ``` + +### Deploy + +```bash +cd cdk +cp .env.example .env +# Edit .env with your GITHUB_SECRET_ARN + +npm install +npx cdk deploy +``` + +### Architecture + +``` +CloudFront (HTTPS) -> ALB (HTTP:80) -> ECS Fargate -> Grafana + strands-metrics -> EFS (metrics.db) +``` + +- **CloudFront** for HTTPS without needing ACM + custom domain +- **EFS with RETAIN policy** so metrics survive redeployments +- **Fargate** (0.5 vCPU / 1 GB) with daily cron via supercronic +- **Anonymous viewer-only** Grafana with `ALLOW_EMBEDDING=true` for iframes + +## GitHub Actions Workflow + +The included workflow (`.github/workflows/community-dashboard.yaml`) runs daily at 06:00 UTC: + +1. Syncs GitHub data (PRs, issues, stars, commits, CI, reviews) +2. Runs garbage collection (sweep) +3. Syncs PyPI/npm download stats +4. Loads goals and team configuration +5. Commits the updated `metrics.db` back to the repository + +Required secret: `METRICS_PAT` -- a GitHub PAT with read access to the `strands-agents` org. + +## Data Flow + +``` +GitHub API (octocrab) PyPI Stats API npm Registry API + | | | + v v v + strands-metrics CLI (Rust) + | + v + metrics.db (SQLite) + | + v + Grafana (SQLite datasource plugin) + | + v + 7 pre-built dashboards in 3 folders +``` diff --git a/community-dashboard/cdk/.env.example b/community-dashboard/cdk/.env.example new file mode 100644 index 0000000..ee01d65 --- /dev/null +++ b/community-dashboard/cdk/.env.example @@ -0,0 +1,3 @@ +# ARN of the Secrets Manager secret holding the GitHub personal access token. +# The secret value should be a plain-text token (not JSON). +GITHUB_SECRET_ARN=arn:aws:secretsmanager:us-west-2:ACCOUNT:secret:strands-grafana/github-token diff --git a/community-dashboard/cdk/bin/app.ts b/community-dashboard/cdk/bin/app.ts new file mode 100644 index 0000000..ef3cbcf --- /dev/null +++ b/community-dashboard/cdk/bin/app.ts @@ -0,0 +1,24 @@ +#!/usr/bin/env node +import "source-map-support/register"; +import * as dotenv from "dotenv"; +import * as cdk from "aws-cdk-lib"; +import { CommunityDashboardStack } from "../lib/community-dashboard-stack"; + +// Load environment variables from .env file (if present) +dotenv.config(); + +const app = new cdk.App(); + +const env = { + account: process.env.CDK_DEFAULT_ACCOUNT, + region: process.env.CDK_DEFAULT_REGION ?? process.env.AWS_REGION ?? "us-west-2", +}; + +new CommunityDashboardStack(app, "CommunityDashboardStack", { + env, + description: + "Community Dashboard — GitHub metrics collection and dashboards for strands-agents org", + tags: { + Project: "community-dashboard", + }, +}); diff --git a/community-dashboard/cdk/cdk.json b/community-dashboard/cdk/cdk.json new file mode 100644 index 0000000..c820084 --- /dev/null +++ b/community-dashboard/cdk/cdk.json @@ -0,0 +1,26 @@ +{ + "app": "npx ts-node --prefer-ts-exts bin/app.ts", + "watch": { + "include": ["**"], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": ["aws"], + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/aws-iam:standardizedServicePrincipals": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": false + } +} diff --git a/community-dashboard/cdk/lib/community-dashboard-stack.ts b/community-dashboard/cdk/lib/community-dashboard-stack.ts new file mode 100644 index 0000000..2d96771 --- /dev/null +++ b/community-dashboard/cdk/lib/community-dashboard-stack.ts @@ -0,0 +1,209 @@ +import * as cdk from "aws-cdk-lib"; +import * as ec2 from "aws-cdk-lib/aws-ec2"; +import * as ecs from "aws-cdk-lib/aws-ecs"; +import * as efs from "aws-cdk-lib/aws-efs"; +import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2"; +import * as cloudfront from "aws-cdk-lib/aws-cloudfront"; +import * as origins from "aws-cdk-lib/aws-cloudfront-origins"; +import * as logs from "aws-cdk-lib/aws-logs"; +import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"; +import { Construct } from "constructs"; +import * as path from "path"; + +export class CommunityDashboardStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + // ── Secrets Manager ────────────────────────────────────────────────── + // The GitHub PAT must already exist in Secrets Manager as a plain-text + // secret. Pass the ARN via the GITHUB_SECRET_ARN env var or CDK context. + const secretArn = + process.env.GITHUB_SECRET_ARN ?? + this.node.tryGetContext("githubSecretArn"); + + if (!secretArn) { + throw new Error( + "GITHUB_SECRET_ARN environment variable or 'githubSecretArn' CDK context must be set.\n" + + "Create the secret first:\n" + + ' aws secretsmanager create-secret --name strands-grafana/github-token --secret-string "ghp_xxx" --region us-west-2' + ); + } + + const githubSecret = secretsmanager.Secret.fromSecretCompleteArn( + this, + "GitHubTokenSecret", + secretArn + ); + + // ── VPC ────────────────────────────────────────────────────────────── + const vpc = new ec2.Vpc(this, "Vpc", { + maxAzs: 2, + natGateways: 1, + }); + + // ── EFS (persistent storage for metrics.db) ───────────────────────── + const fileSystem = new efs.FileSystem(this, "MetricsFs", { + vpc, + removalPolicy: cdk.RemovalPolicy.RETAIN, + performanceMode: efs.PerformanceMode.GENERAL_PURPOSE, + lifecyclePolicy: efs.LifecyclePolicy.AFTER_30_DAYS, + encrypted: true, + }); + + const accessPoint = fileSystem.addAccessPoint("GrafanaData", { + path: "/grafana-data", + createAcl: { + ownerUid: "0", + ownerGid: "0", + permissions: "755", + }, + posixUser: { + uid: "0", + gid: "0", + }, + }); + + // ── ECS Cluster ───────────────────────────────────────────────────── + const cluster = new ecs.Cluster(this, "Cluster", { + vpc, + containerInsights: true, + }); + + // ── Task Definition ───────────────────────────────────────────────── + const taskDef = new ecs.FargateTaskDefinition(this, "TaskDef", { + cpu: 512, + memoryLimitMiB: 1024, + }); + + // Mount EFS volume + taskDef.addVolume({ + name: "metrics-data", + efsVolumeConfiguration: { + fileSystemId: fileSystem.fileSystemId, + transitEncryption: "ENABLED", + authorizationConfig: { + accessPointId: accessPoint.accessPointId, + iam: "ENABLED", + }, + }, + }); + + // Grant EFS access to the task role + fileSystem.grant( + taskDef.taskRole, + "elasticfilesystem:ClientMount", + "elasticfilesystem:ClientWrite", + "elasticfilesystem:ClientRootAccess" + ); + + // Container definition — built from the unified Dockerfile + const container = taskDef.addContainer("grafana", { + image: ecs.ContainerImage.fromAsset( + path.join(__dirname, "../../"), + { + file: "docker/Dockerfile", + platform: cdk.aws_ecr_assets.Platform.LINUX_AMD64, + } + ), + logging: ecs.LogDrivers.awsLogs({ + streamPrefix: "community-dashboard", + logRetention: logs.RetentionDays.TWO_WEEKS, + }), + portMappings: [{ containerPort: 3000 }], + secrets: { + GITHUB_TOKEN: ecs.Secret.fromSecretsManager(githubSecret), + }, + healthCheck: { + command: [ + "CMD-SHELL", + "wget -qO- http://localhost:3000/api/health || exit 1", + ], + interval: cdk.Duration.seconds(30), + timeout: cdk.Duration.seconds(5), + retries: 3, + startPeriod: cdk.Duration.seconds(120), + }, + }); + + container.addMountPoints({ + sourceVolume: "metrics-data", + containerPath: "/var/lib/grafana/data", + readOnly: false, + }); + + // ── Fargate Service + ALB ─────────────────────────────────────────── + const service = new ecs.FargateService(this, "Service", { + cluster, + taskDefinition: taskDef, + desiredCount: 1, + assignPublicIp: false, + platformVersion: ecs.FargatePlatformVersion.LATEST, + }); + + // Allow the service to reach EFS + service.connections.allowTo(fileSystem, ec2.Port.tcp(2049), "EFS access"); + + // Application Load Balancer + const alb = new elbv2.ApplicationLoadBalancer(this, "Alb", { + vpc, + internetFacing: true, + }); + + const listener = alb.addListener("HttpListener", { + port: 80, + }); + + listener.addTargets("GrafanaTarget", { + port: 3000, + protocol: elbv2.ApplicationProtocol.HTTP, + targets: [service], + healthCheck: { + path: "/api/health", + interval: cdk.Duration.seconds(30), + healthyThresholdCount: 2, + unhealthyThresholdCount: 3, + }, + deregistrationDelay: cdk.Duration.seconds(30), + }); + + // ── Outputs ───────────────────────────────────────────────────────── + // CloudFront distribution — provides HTTPS on *.cloudfront.net + const distribution = new cloudfront.Distribution(this, "Distribution", { + defaultBehavior: { + origin: new origins.HttpOrigin(alb.loadBalancerDnsName, { + protocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY, + }), + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED, + originRequestPolicy: cloudfront.OriginRequestPolicy.ALL_VIEWER, + allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL, + }, + }); + + new cdk.CfnOutput(this, "GrafanaUrl", { + value: `https://${distribution.distributionDomainName}`, + description: "Grafana dashboard URL (HTTPS via CloudFront)", + }); + + new cdk.CfnOutput(this, "AlbUrl", { + value: `http://${alb.loadBalancerDnsName}`, + description: "Grafana dashboard URL (ALB, HTTP only)", + }); + + new cdk.CfnOutput(this, "EfsFileSystemId", { + value: fileSystem.fileSystemId, + description: "EFS file system ID (persistent metrics.db storage)", + }); + + new cdk.CfnOutput(this, "ClusterArn", { + value: cluster.clusterArn, + description: "ECS cluster ARN", + }); + + new cdk.CfnOutput(this, "CreateSecretCommand", { + value: + 'aws secretsmanager create-secret --name strands-grafana/github-token --secret-string "ghp_xxx" --region us-west-2', + description: "Command to create the GitHub token secret (one-time)", + }); + } +} diff --git a/community-dashboard/cdk/package.json b/community-dashboard/cdk/package.json new file mode 100644 index 0000000..4f8d12e --- /dev/null +++ b/community-dashboard/cdk/package.json @@ -0,0 +1,26 @@ +{ + "name": "community-dashboard-cdk", + "version": "1.0.0", + "description": "AWS CDK infrastructure for community dashboard — GitHub metrics and Grafana", + "bin": { + "cdk": "bin/app.js" + }, + "scripts": { + "build": "tsc", + "watch": "tsc -w", + "cdk": "cdk", + "synth": "cdk synth", + "deploy": "cdk deploy", + "destroy": "cdk destroy" + }, + "dependencies": { + "aws-cdk-lib": "^2.170.0", + "constructs": "^10.0.0", + "dotenv": "^16.0.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "aws-cdk": "^2.170.0", + "typescript": "^5.0.0" + } +} diff --git a/community-dashboard/cdk/tsconfig.json b/community-dashboard/cdk/tsconfig.json new file mode 100644 index 0000000..10368b0 --- /dev/null +++ b/community-dashboard/cdk/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "commonjs", + "lib": ["ES2022"], + "declaration": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": false, + "inlineSourceMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictPropertyInitialization": false, + "typeRoots": ["./node_modules/@types"], + "outDir": "dist", + "rootDir": "." + }, + "exclude": ["node_modules", "cdk.out", "dist"] +} diff --git a/community-dashboard/docker-compose.yaml b/community-dashboard/docker-compose.yaml new file mode 100644 index 0000000..56ed819 --- /dev/null +++ b/community-dashboard/docker-compose.yaml @@ -0,0 +1,21 @@ +services: + grafana: + image: grafana/grafana:latest + container_name: grafana-sqlite-viz + user: "0:0" + ports: + - "3000:3000" + volumes: + - .:/mnt/data:ro + - ./provisioning/datasources:/etc/grafana/provisioning/datasources + - ./provisioning/dashboards:/etc/grafana/provisioning/dashboards + environment: + - GF_INSTALL_PLUGINS=frser-sqlite-datasource + - GF_PLUGIN_FRSER_SQLITE_DATASOURCE_ALLOW_LOCAL_MODE=true + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer + - GF_AUTH_BASIC_ENABLED=false + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_USERS_ALLOW_SIGN_UP=false + - GF_SECURITY_ALLOW_EMBEDDING=true + restart: always diff --git a/community-dashboard/docker/Dockerfile b/community-dashboard/docker/Dockerfile new file mode 100644 index 0000000..ffbf442 --- /dev/null +++ b/community-dashboard/docker/Dockerfile @@ -0,0 +1,69 @@ +# ============================================================================= +# Stage 1: Build the strands-metrics Rust binary +# ============================================================================= +FROM rust:1.88-alpine AS builder + +RUN apk add --no-cache musl-dev pkgconfig openssl-dev openssl-libs-static + +WORKDIR /build + +# Copy the Rust project source +COPY Cargo.toml Cargo.lock* ./ +COPY src/ ./src/ + +# Build in release mode (statically linked against musl) +RUN cargo build --release + +# ============================================================================= +# Stage 2: Unified Grafana + metrics sync image +# ============================================================================= +FROM grafana/grafana:latest + +USER root + +# Install ca-certificates and curl for downloading supercronic +RUN apk add --no-cache ca-certificates curl + +# Install supercronic (cron replacement designed for containers) +ARG SUPERCRONIC_VERSION=v0.2.43 +ARG SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/${SUPERCRONIC_VERSION}/supercronic-linux-amd64 +RUN curl -fsSL "${SUPERCRONIC_URL}" -o /usr/local/bin/supercronic \ + && chmod +x /usr/local/bin/supercronic + +# Copy the compiled strands-metrics binary +COPY --from=builder /build/target/release/strands-metrics /usr/local/bin/strands-metrics + +# Copy Grafana provisioning configs +COPY provisioning/datasources/ /etc/grafana/provisioning/datasources/ +COPY provisioning/dashboards/ /etc/grafana/provisioning/dashboards/ + +# Copy configuration files for goals, team, and packages +COPY goals.yaml /etc/strands/goals.yaml +COPY team.yaml /etc/strands/team.yaml +COPY packages.yaml /etc/strands/packages.yaml + +# Copy entrypoint script +COPY docker/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +# Create the data directory for EFS / local mount +RUN mkdir -p /var/lib/grafana/data + +# Bundle a pre-built metrics.db so the first boot doesn't need a long backfill. +# The entrypoint will copy this to the EFS volume if no DB exists yet. +# The wildcard pattern makes this a no-op if the file doesn't exist. +COPY docker/data/metrics.d[b] /seed/ + +# Grafana configuration via environment variables +ENV GF_INSTALL_PLUGINS=frser-sqlite-datasource +ENV GF_PLUGIN_FRSER_SQLITE_DATASOURCE_ALLOW_LOCAL_MODE=true +ENV GF_AUTH_ANONYMOUS_ENABLED=true +ENV GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer +ENV GF_AUTH_BASIC_ENABLED=false +ENV GF_AUTH_DISABLE_LOGIN_FORM=true +ENV GF_USERS_ALLOW_SIGN_UP=false +ENV GF_SECURITY_ALLOW_EMBEDDING=true + +EXPOSE 3000 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/community-dashboard/docker/docker-compose.local.yaml b/community-dashboard/docker/docker-compose.local.yaml new file mode 100644 index 0000000..0bc3f43 --- /dev/null +++ b/community-dashboard/docker/docker-compose.local.yaml @@ -0,0 +1,21 @@ +# Local development docker-compose +# Build and run the unified Grafana + metrics-sync container locally. +# +# Usage: +# GITHUB_TOKEN=ghp_xxx docker compose -f docker/docker-compose.local.yaml up --build +# +# Then open http://localhost:3000 + +services: + grafana: + build: + context: .. + dockerfile: docker/Dockerfile + container_name: community-dashboard + ports: + - "3000:3000" + volumes: + - ./data:/var/lib/grafana/data + environment: + - GITHUB_TOKEN=${GITHUB_TOKEN} + restart: unless-stopped diff --git a/community-dashboard/docker/entrypoint.sh b/community-dashboard/docker/entrypoint.sh new file mode 100644 index 0000000..2dc35c3 --- /dev/null +++ b/community-dashboard/docker/entrypoint.sh @@ -0,0 +1,65 @@ +#!/bin/sh +set -e + +DB_PATH="/var/lib/grafana/data/metrics.db" +CONFIG_DIR="/etc/strands" + +# ── Initial backfill ──────────────────────────────────────────────────────── +# If the database doesn't exist or is empty on the EFS volume, seed it from +# the pre-built copy baked into the image. The daily cron handles incremental +# updates from there — no hours-long backfill needed on first boot. +SEED_PATH="/seed/metrics.db" + +if [ ! -f "$DB_PATH" ] || [ ! -s "$DB_PATH" ]; then + if [ -f "$SEED_PATH" ]; then + echo "[entrypoint] Seeding metrics.db from bundled snapshot..." + cp "$SEED_PATH" "$DB_PATH" + echo "[entrypoint] Seed copy complete ($(du -h "$DB_PATH" | cut -f1))." + # Run a quick incremental sync to pick up anything newer than the snapshot + if [ -n "$GITHUB_TOKEN" ]; then + echo "[entrypoint] Running incremental sync to catch up..." + strands-metrics --db-path "$DB_PATH" sync || \ + echo "[entrypoint] WARNING: Incremental sync failed (will retry on next cron run)." + fi + else + echo "[entrypoint] No seed DB found — running full sync..." + if [ -z "$GITHUB_TOKEN" ]; then + echo "[entrypoint] WARNING: GITHUB_TOKEN is not set. Skipping sync." + else + strands-metrics --db-path "$DB_PATH" sync || \ + echo "[entrypoint] WARNING: Initial sync failed (will retry on next cron run)." + fi + fi +else + echo "[entrypoint] metrics.db already exists with data — skipping seed." +fi + +# ── Load configuration ───────────────────────────────────────────────────── +# Load goals and team config into the database on every startup +echo "[entrypoint] Loading goals configuration..." +strands-metrics --db-path "$DB_PATH" load-goals "$CONFIG_DIR/goals.yaml" || \ + echo "[entrypoint] WARNING: Failed to load goals." + +echo "[entrypoint] Loading team configuration..." +strands-metrics --db-path "$DB_PATH" load-team "$CONFIG_DIR/team.yaml" || \ + echo "[entrypoint] WARNING: Failed to load team." + +# ── Sync package downloads ───────────────────────────────────────────────── +echo "[entrypoint] Syncing package downloads..." +strands-metrics --db-path "$DB_PATH" sync-downloads --config-path "$CONFIG_DIR/packages.yaml" || \ + echo "[entrypoint] WARNING: Failed to sync downloads." + +# ── Cron schedule ─────────────────────────────────────────────────────────── +# Sync daily at 06:00 UTC. Output is forwarded to container stdout/stderr +# via /proc/1/fd/1 so it shows up in docker logs / CloudWatch. +CRONTAB="/tmp/crontab" +cat > "$CRONTAB" <<'CRONEOF' +0 6 * * * strands-metrics --db-path /var/lib/grafana/data/metrics.db sync >> /proc/1/fd/1 2>&1 && strands-metrics --db-path /var/lib/grafana/data/metrics.db sweep >> /proc/1/fd/1 2>&1 && strands-metrics --db-path /var/lib/grafana/data/metrics.db sync-downloads --config-path /etc/strands/packages.yaml >> /proc/1/fd/1 2>&1 && strands-metrics --db-path /var/lib/grafana/data/metrics.db load-goals /etc/strands/goals.yaml >> /proc/1/fd/1 2>&1 && strands-metrics --db-path /var/lib/grafana/data/metrics.db load-team /etc/strands/team.yaml >> /proc/1/fd/1 2>&1 +CRONEOF + +echo "[entrypoint] Starting supercronic (daily sync at 06:00 UTC)..." +supercronic "$CRONTAB" & + +# ── Start Grafana ─────────────────────────────────────────────────────────── +echo "[entrypoint] Launching Grafana..." +exec /run.sh diff --git a/community-dashboard/goals.yaml b/community-dashboard/goals.yaml new file mode 100644 index 0000000..c7b59c6 --- /dev/null +++ b/community-dashboard/goals.yaml @@ -0,0 +1,111 @@ +# Strands Project Goals Configuration +# These thresholds appear as goal lines in Grafana dashboards +# Edit values here and run `strands-metrics load-goals` to update +# +# NOTE: Only rate/percentage/time-based metrics have goals. +# Count-based metrics (open PRs, contributors, etc.) are excluded +# because they scale with the number of repos selected. +# +# ============================================================================ +# Configuration Reference +# ============================================================================ +# +# Each goal requires: +# - value: The target threshold value +# - label: Display label for the goal line (shown in Grafana legend) +# - direction: How to interpret values relative to the goal +# * "lower_is_better" - green below goal, red above (e.g., time metrics) +# * "higher_is_better" - green above goal, red below (e.g., percentages) +# - warning_ratio: (optional) Multiplier for warning threshold +# * Default: 0.75 for lower_is_better, 0.70 for higher_is_better +# * Example: warning_ratio: 0.75 with goal 24 = warning at 18 +# +# ============================================================================ +# Metric Definitions +# ============================================================================ +# +# Time Metrics (hours): +# avg_merge_time_hours - Average time from PR open to merge +# cycle_time_hours - Time from first commit to merge (rolling average) +# time_to_first_review - Time until first review is submitted on a PR +# time_to_first_response - Time until first comment/review on issues/PRs +# +# Quality Metrics (percentages): +# ci_failure_rate_percent - Percentage of PRs with failed CI checks +# pr_acceptance_rate_min - Percentage of PRs merged vs closed without merge +# +# Community Metrics (percentages): +# community_pr_percent_min - Percentage of merged PRs from non-org members +# contributor_retention_min - Percentage of contributors who return +# +# Aggregate Metrics (counts): +# stale_prs_max - Maximum acceptable stale PRs (open 7+ days without activity) +# +# ============================================================================ + +goals: + # --------------------------------------------------------------------------- + # Time Metrics (hours) - lower is better + # --------------------------------------------------------------------------- + avg_merge_time_hours: + value: 24 + label: "Goal (24h)" + direction: lower_is_better + # warning at 18h (default 0.75 ratio) + + cycle_time_hours: + value: 336 + label: "Goal (14d)" + direction: lower_is_better + # warning at 252h / 10.5d (default 0.75 ratio) + + time_to_first_review_hours: + value: 72 + label: "Goal (72h)" + direction: lower_is_better + # warning at 54h (default 0.75 ratio) + + time_to_first_response_hours: + value: 24 + label: "Goal (24h)" + direction: lower_is_better + warning_ratio: 0.75 # warning at 18h + + # --------------------------------------------------------------------------- + # Quality Metrics (percentages) + # --------------------------------------------------------------------------- + ci_failure_rate_percent: + value: 30 + label: "Goal (30%)" + direction: lower_is_better + # warning at 22.5% (default 0.75 ratio) + + pr_acceptance_rate_min: + value: 60 + label: "Goal (60%)" + direction: higher_is_better + # warning at 42% (default 0.70 ratio) + + # --------------------------------------------------------------------------- + # Community Metrics (percentages) + # --------------------------------------------------------------------------- + community_pr_percent_min: + value: 20 + label: "Goal (20%)" + direction: higher_is_better + warning_ratio: 0.70 # warning at 14% + + contributor_retention_min: + value: 25 + label: "Goal (25%)" + direction: higher_is_better + # warning at 17.5% (default 0.70 ratio) + + # --------------------------------------------------------------------------- + # Executive Dashboard Thresholds (org-level aggregates) + # --------------------------------------------------------------------------- + stale_prs_max: + value: 15 + label: "Goal (<15)" + direction: lower_is_better + warning_ratio: 0.33 # warning at 5 diff --git a/community-dashboard/packages.yaml b/community-dashboard/packages.yaml new file mode 100644 index 0000000..c94f709 --- /dev/null +++ b/community-dashboard/packages.yaml @@ -0,0 +1,26 @@ +# Package Download Tracking Configuration +# Maps GitHub repos to their published packages for download tracking +# Used for filtering the Adoption dashboard by repo + +repo_mappings: + sdk-python: + - package: strands-agents + registry: pypi + sdk-typescript: + - package: "@strands-agents/sdk" + registry: npm + tools: + - package: strands-agents-tools + registry: pypi + agent-sop: + - package: strands-agents-sops + registry: pypi + agent-builder: + - package: strands-agents-builder + registry: pypi + evals: + - package: strands-agents-evals + registry: pypi + mcp-server: + - package: strands-agents-mcp-server + registry: pypi diff --git a/community-dashboard/provisioning/dashboards/dashboards.yaml b/community-dashboard/provisioning/dashboards/dashboards.yaml new file mode 100644 index 0000000..bef06ef --- /dev/null +++ b/community-dashboard/provisioning/dashboards/dashboards.yaml @@ -0,0 +1,29 @@ +apiVersion: 1 + +providers: + - name: "General" + orgId: 1 + folder: "" + type: file + disableDeletion: false + updateIntervalSeconds: 60 + options: + path: /etc/grafana/provisioning/dashboards/general + + - name: "SDKs" + orgId: 1 + folder: "SDKs" + type: file + disableDeletion: false + updateIntervalSeconds: 60 + options: + path: /etc/grafana/provisioning/dashboards/sdks + + - name: "Operations" + orgId: 1 + folder: "Operations" + type: file + disableDeletion: false + updateIntervalSeconds: 60 + options: + path: /etc/grafana/provisioning/dashboards/operations diff --git a/community-dashboard/provisioning/dashboards/general/executive.json b/community-dashboard/provisioning/dashboards/general/executive.json new file mode 100644 index 0000000..a9fa4c7 --- /dev/null +++ b/community-dashboard/provisioning/dashboards/general/executive.json @@ -0,0 +1,1398 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "panels": [], + "title": "Key Performance Indicators", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Pull requests merged in the last 7 days compared to the previous 7 days.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date('now', '-14 days')) as INTEGER) as time,\n (SELECT COUNT(*) FROM pull_requests WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-14 days') AND date(merged_at) < date('now', '-7 days')) as \"PRs Merged\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT COUNT(*) FROM pull_requests WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-7 days')) as \"PRs Merged\"", + "queryType": "time series", + "rawQueryText": "SELECT \n CAST(strftime('%s', date('now', '-14 days')) as INTEGER) as time,\n (SELECT COUNT(*) FROM pull_requests WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-14 days') AND date(merged_at) < date('now', '-7 days')) as \"PRs Merged\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT COUNT(*) FROM pull_requests WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-7 days')) as \"PRs Merged\"", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PRs Merged (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Average hours until first response on issues/PRs.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 18.0 + }, + { + "color": "red", + "value": 24.0 + } + ] + }, + "unit": "h" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 1 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "inverted", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date('now', '-14 days')) as INTEGER) as time,\n (SELECT ROUND(AVG(time_to_first_response), 1) FROM daily_metrics WHERE date >= date('now', '-14 days') AND date < date('now', '-7 days') AND time_to_first_response > 0) as \"Response Time\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT ROUND(AVG(time_to_first_response), 1) FROM daily_metrics WHERE date >= date('now', '-7 days') AND time_to_first_response > 0) as \"Response Time\"", + "queryType": "time series", + "rawQueryText": "SELECT \n CAST(strftime('%s', date('now', '-14 days')) as INTEGER) as time,\n (SELECT ROUND(AVG(time_to_first_response), 1) FROM daily_metrics WHERE date >= date('now', '-14 days') AND date < date('now', '-7 days') AND time_to_first_response > 0) as \"Response Time\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT ROUND(AVG(time_to_first_response), 1) FROM daily_metrics WHERE date >= date('now', '-7 days') AND time_to_first_response > 0) as \"Response Time\"", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'time_to_first_response_hours'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'time_to_first_response_hours'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Time to First Response (7d)", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Percentage of merged PRs from community (non-org) contributors.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 14.0 + }, + { + "color": "green", + "value": 20.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 1 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date('now', '-60 days')) as INTEGER) as time,\n (SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1)\n FROM pull_requests\n WHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-60 days')\n AND date(merged_at) < date('now', '-30 days')) as \"Community %\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1)\n FROM pull_requests\n WHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-30 days')) as \"Community %\"", + "queryType": "time series", + "rawQueryText": "SELECT \n CAST(strftime('%s', date('now', '-60 days')) as INTEGER) as time,\n (SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1)\n FROM pull_requests\n WHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-60 days')\n AND date(merged_at) < date('now', '-30 days')) as \"Community %\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1)\n FROM pull_requests\n WHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-30 days')) as \"Community %\"", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Community PR % (30d)", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total package downloads in the last 7 days across PyPI and npm.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 1 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date('now', '-14 days')) as INTEGER) as time,\n (SELECT SUM(downloads) FROM package_downloads WHERE date >= date('now', '-14 days') AND date < date('now', '-7 days')) as \"Downloads\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT SUM(downloads) FROM package_downloads WHERE date >= date('now', '-7 days')) as \"Downloads\"", + "queryType": "time series", + "rawQueryText": "SELECT \n CAST(strftime('%s', date('now', '-14 days')) as INTEGER) as time,\n (SELECT SUM(downloads) FROM package_downloads WHERE date >= date('now', '-14 days') AND date < date('now', '-7 days')) as \"Downloads\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT SUM(downloads) FROM package_downloads WHERE date >= date('now', '-7 days')) as \"Downloads\"", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Downloads (7d)", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 10, + "panels": [], + "title": "Adoption", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Cumulative downloads across all packages and registries.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 5, + "x": 0, + "y": 7 + }, + "id": 11, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT SUM(downloads) as value FROM package_downloads", + "queryType": "table", + "rawQueryText": "SELECT SUM(downloads) as value FROM package_downloads", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Downloads", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Weekly download trends across all packages.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 13, + "x": 5, + "y": 7 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(downloads) as \"Weekly Downloads\"\nFROM package_downloads\nWHERE date >= date('now', '-90 days')\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time", + "queryType": "time series", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(downloads) as \"Weekly Downloads\"\nFROM package_downloads\nWHERE date >= date('now', '-90 days')\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Weekly Downloads", + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Download distribution between PyPI and npm.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pypi" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3572A5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "npm" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#f7df1e", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 13, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "displayMode": "list", + "placement": "right", + "showLegend": true, + "values": [] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT registry, SUM(downloads) as downloads\nFROM package_downloads\nGROUP BY registry", + "queryType": "table", + "rawQueryText": "SELECT registry, SUM(downloads) as downloads\nFROM package_downloads\nGROUP BY registry", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Platform Split", + "transformations": [ + { + "id": "rowsToFields", + "options": { + "mappings": [ + { + "fieldName": "registry", + "handlerKey": "field.name" + }, + { + "fieldName": "downloads", + "handlerKey": "field.value" + } + ] + } + } + ], + "type": "piechart" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 20, + "panels": [], + "title": "Trends", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Average hours from PR open to merge (14-day rolling average).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 252.0 + }, + { + "color": "red", + "value": 336.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Goal (14d)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 21, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH daily_avg AS (\n SELECT \n date(merged_at) as merge_date,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) as avg_hours\n FROM pull_requests\n WHERE merged_at IS NOT NULL\n AND date(merged_at) >= date('now', '-104 days')\n GROUP BY date(merged_at)\n)\nSELECT \n CAST(strftime('%s', merge_date) as INTEGER) as time,\n AVG(avg_hours) OVER (ORDER BY merge_date ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as \"Cycle Time\"\nFROM daily_avg\nWHERE merge_date >= date('now', '-90 days')\nORDER BY merge_date", + "queryType": "time series", + "rawQueryText": "WITH daily_avg AS (\n SELECT \n date(merged_at) as merge_date,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) as avg_hours\n FROM pull_requests\n WHERE merged_at IS NOT NULL\n AND date(merged_at) >= date('now', '-104 days')\n GROUP BY date(merged_at)\n)\nSELECT \n CAST(strftime('%s', merge_date) as INTEGER) as time,\n AVG(avg_hours) OVER (ORDER BY merge_date ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as \"Cycle Time\"\nFROM daily_avg\nWHERE merge_date >= date('now', '-90 days')\nORDER BY merge_date", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n (SELECT label FROM goals WHERE metric = 'cycle_time_hours') as metric,\n (SELECT value FROM goals WHERE metric = 'cycle_time_hours') as value\nFROM (\n SELECT DISTINCT date(merged_at) as date\n FROM pull_requests\n WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-90 days')\n)\nORDER BY date", + "queryType": "time series", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n (SELECT label FROM goals WHERE metric = 'cycle_time_hours') as metric,\n (SELECT value FROM goals WHERE metric = 'cycle_time_hours') as value\nFROM (\n SELECT DISTINCT date(merged_at) as date\n FROM pull_requests\n WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-90 days')\n)\nORDER BY date", + "refId": "Goal", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Cycle Time (14-Day Rolling)", + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Cumulative unique contributors over time.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Community" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date,\n MAX(CASE WHEN json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) as is_org_member\n FROM pull_requests\n WHERE merged_at IS NOT NULL\n GROUP BY author\n),\ndates AS (\n SELECT DISTINCT date(merged_at) as date\n FROM pull_requests\n WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-90 days')\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n (SELECT COUNT(*) FROM first_contributions WHERE first_pr_date <= d.date) as \"Total\",\n (SELECT COUNT(*) FROM first_contributions WHERE first_pr_date <= d.date AND is_org_member = 0) as \"Community\"\nFROM dates d\nORDER BY d.date", + "queryType": "time series", + "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date,\n MAX(CASE WHEN json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) as is_org_member\n FROM pull_requests\n WHERE merged_at IS NOT NULL\n GROUP BY author\n),\ndates AS (\n SELECT DISTINCT date(merged_at) as date\n FROM pull_requests\n WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-90 days')\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n (SELECT COUNT(*) FROM first_contributions WHERE first_pr_date <= d.date) as \"Total\",\n (SELECT COUNT(*) FROM first_contributions WHERE first_pr_date <= d.date AND is_org_member = 0) as \"Community\"\nFROM dates d\nORDER BY d.date", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Cumulative Contributors", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 30, + "panels": [], + "title": "Current State", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current count of open pull requests vs 7 days ago.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 23 + }, + "id": 31, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "inverted", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date('now', '-7 days')) as INTEGER) as time,\n (SELECT SUM(open_prs_count) FROM daily_metrics WHERE date = date('now', '-7 days')) as \"Open PRs\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT COUNT(*) FROM pull_requests WHERE state = 'open') as \"Open PRs\"", + "queryType": "time series", + "rawQueryText": "SELECT \n CAST(strftime('%s', date('now', '-7 days')) as INTEGER) as time,\n (SELECT SUM(open_prs_count) FROM daily_metrics WHERE date = date('now', '-7 days')) as \"Open PRs\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT COUNT(*) FROM pull_requests WHERE state = 'open') as \"Open PRs\"", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Open PRs", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "PRs open for more than 7 days without merge.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 4.95 + }, + { + "color": "red", + "value": 15.0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 23 + }, + "id": 32, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "inverted", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE state = 'open' \n AND date(created_at) < date('now', '-7 days')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE state = 'open' \n AND date(created_at) < date('now', '-7 days')", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Stale PRs (7d+)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Average hours from PR open to merge (14-day window).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 18.0 + }, + { + "color": "red", + "value": 24.0 + } + ] + }, + "unit": "h" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 23 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "inverted", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date('now', '-28 days')) as INTEGER) as time,\n (SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1)\n FROM pull_requests \n WHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-28 days') \n AND date(merged_at) < date('now', '-14 days')) as \"Merge Time\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1)\n FROM pull_requests \n WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-14 days')) as \"Merge Time\"", + "queryType": "time series", + "rawQueryText": "SELECT \n CAST(strftime('%s', date('now', '-28 days')) as INTEGER) as time,\n (SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1)\n FROM pull_requests \n WHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-28 days') \n AND date(merged_at) < date('now', '-14 days')) as \"Merge Time\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1)\n FROM pull_requests \n WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-14 days')) as \"Merge Time\"", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'avg_merge_time_hours'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'avg_merge_time_hours'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Avg Merge Time", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total GitHub stars across all repositories.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "yellow", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 23 + }, + "id": 34, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date('now', '-7 days')) as INTEGER) as time,\n (SELECT SUM(stars) FROM daily_metrics WHERE date = date('now', '-7 days')) as \"Stars\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT SUM(stars) FROM daily_metrics WHERE date = (SELECT MAX(date) FROM daily_metrics)) as \"Stars\"", + "queryType": "time series", + "rawQueryText": "SELECT \n CAST(strftime('%s', date('now', '-7 days')) as INTEGER) as time,\n (SELECT SUM(stars) FROM daily_metrics WHERE date = date('now', '-7 days')) as \"Stars\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT SUM(stars) FROM daily_metrics WHERE date = (SELECT MAX(date) FROM daily_metrics)) as \"Stars\"", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Stars", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Unique contributors with merged PRs in the last 7 days.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 23 + }, + "id": 35, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date('now', '-14 days')) as INTEGER) as time,\n (SELECT COUNT(DISTINCT author) FROM pull_requests WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-14 days') AND date(merged_at) < date('now', '-7 days')) as \"Contributors\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT COUNT(DISTINCT author) FROM pull_requests WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-7 days')) as \"Contributors\"", + "queryType": "time series", + "rawQueryText": "SELECT \n CAST(strftime('%s', date('now', '-14 days')) as INTEGER) as time,\n (SELECT COUNT(DISTINCT author) FROM pull_requests WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-14 days') AND date(merged_at) < date('now', '-7 days')) as \"Contributors\"\nUNION ALL\nSELECT \n CAST(strftime('%s', date('now')) as INTEGER) as time,\n (SELECT COUNT(DISTINCT author) FROM pull_requests WHERE merged_at IS NOT NULL AND date(merged_at) >= date('now', '-7 days')) as \"Contributors\"", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Active Contributors (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Number of repositories being tracked.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 23 + }, + "id": 36, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(DISTINCT repo) as value FROM pull_requests", + "queryType": "table", + "rawQueryText": "SELECT COUNT(DISTINCT repo) as value FROM pull_requests", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Repos", + "type": "stat" + } + ], + "preload": false, + "schemaVersion": 40, + "tags": [ + "executive", + "summary" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-90d", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Executive Summary", + "uid": "executive-summary", + "version": 1 +} \ No newline at end of file diff --git a/community-dashboard/provisioning/dashboards/general/health.json b/community-dashboard/provisioning/dashboards/general/health.json new file mode 100644 index 0000000..711ab59 --- /dev/null +++ b/community-dashboard/provisioning/dashboards/general/health.json @@ -0,0 +1,12164 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 4, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 200, + "panels": [], + "title": "Key Metrics", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current count of open pull requests. This is a point-in-time snapshot, not affected by date range.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 1 + }, + "id": 201, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value FROM pull_requests WHERE state = 'open' AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value FROM pull_requests WHERE state = 'open' AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Open PRs (Current)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Average hours from PR open to merge. Fixed 14-day lookback - does not change with date picker. Goal threshold shown on related charts.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 18.0 + }, + { + "color": "red", + "value": 24.0 + } + ] + }, + "unit": "h" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 1 + }, + "id": 202, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-14 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-14 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'avg_merge_time_hours'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'avg_merge_time_hours'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Avg Merge Time (14d)", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Percentage of merged PRs from community contributors. Fixed 30-day lookback - does not change with date picker. Goal threshold shown on related charts.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 14.0 + }, + { + "color": "green", + "value": 20.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 203, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-30 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-30 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Community PR % (30d)", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Unique PR authors in the last 7 days. Fixed lookback - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 1 + }, + "id": 204, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(DISTINCT author) as value\nFROM pull_requests \nWHERE date(created_at) >= date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(DISTINCT author) as value\nFROM pull_requests \nWHERE date(created_at) >= date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Active Contributors (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "PRs merged in the last 7 days. Fixed lookback - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 1 + }, + "id": 205, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Merged (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Open PRs with no activity in 7+ days. Fixed threshold - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 4.95 + }, + { + "color": "red", + "value": 15.0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 1 + }, + "id": 206, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE state = 'open'\n AND date(updated_at) < date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE state = 'open'\n AND date(updated_at) < date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'stale_prs_max'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'stale_prs_max'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Stale PRs (7d+)", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 100, + "panels": [], + "title": "Volume", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 101, + "panels": [], + "title": "Speed", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 61 + }, + "id": 102, + "panels": [], + "title": "Quality", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 78 + }, + "id": 103, + "panels": [], + "title": "Community", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current count of open pull requests across selected repositories. Point-in-time snapshot.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Open PRs (Current)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current cumulative count of GitHub stars. Point-in-time snapshot.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 79 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Stars (Current)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Count of unique community contributors who created PRs in the rolling 7-day window ending on each date.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 79 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "queryType": "table", + "rawQueryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Weekly Active Community Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 30-day rolling average percentage of merged PRs from community contributors.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (20%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 87 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Community PR Share (30-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of PRs closed without being merged.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 87 + }, + "id": 9, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Rejected PRs (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of PRs that waited >48 hours for first review.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 53 + }, + "id": 19, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(first_review_at)) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(first_review_at), repo\nORDER BY first_review_at ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(first_review_at)) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(first_review_at), repo\nORDER BY first_review_at ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Slow Reviews (>48h Wait)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 7-day rolling average of CI failure rate.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 22.5 + }, + { + "color": "red", + "value": 30.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (30%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 62 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "CI Failure Rate (7-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 7-day rolling average of lines changed per day. Days >10k lines filtered out.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 70 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Code Churn (7-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 30-day rolling average of (PRs merged / PRs opened) × 100%.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 42.0 + }, + { + "color": "green", + "value": 60.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (60%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 62 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN (${repo:singlequote})\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "PR Acceptance Rate (30-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Week-over-week change in open PR count.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": true, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 70 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Backlog Growth (WoW)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of new GitHub Issues opened.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 2, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Opened (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of GitHub Issues closed.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 3, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Closed (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of pull requests merged.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 1, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PRs Merged (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Average hours until first response on issues/PRs.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 18.0 + }, + { + "color": "red", + "value": 24.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (24h)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 53 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND avg_issue_resolution_time > 0\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND avg_issue_resolution_time > 0\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Time to First Response", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 14-day rolling average hours from PR open to merge, by contributor type.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 252.0 + }, + { + "color": "red", + "value": 336.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (14d)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 45 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Cycle Time (14-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 14-day rolling average hours until first PR review, by contributor type.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 54.0 + }, + { + "color": "red", + "value": 72.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (72h)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 45 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Time to First Review (14-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 95 + }, + "id": 104, + "panels": [], + "title": "Contributor Insights", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of first-time vs returning contributors.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "New Contributors" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Returning Contributors" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 96 + }, + "id": 21, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(created_at), author\n)\nSELECT \n CAST(strftime('%s', dc.pr_date) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY dc.pr_date, metric\nORDER BY dc.pr_date ASC", + "queryType": "table", + "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY date(created_at), author\n)\nSELECT \n CAST(strftime('%s', dc.pr_date) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY dc.pr_date, metric\nORDER BY dc.pr_date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "New vs Returning Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Percentage of contributors from 30-60 days ago who returned in last 30 days.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Retention %", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 17.5 + }, + { + "color": "green", + "value": 25.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Goal (25%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 96 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "mean", + "last" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH date_series AS (\n SELECT DISTINCT date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "queryType": "table", + "rawQueryText": "WITH date_series AS (\n SELECT DISTINCT date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Contributor Retention Rate", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Leaderboard of community contributors by PR count.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pr_count" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "min", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "repos" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 104 + }, + "id": 23, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "pr_count" + } + ] + }, + "targets": [ + { + "queryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", + "queryType": "table", + "rawQueryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Top Community Contributors", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Community contributor count per repository.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 104 + }, + "id": 24, + "options": { + "barRadius": 0.1, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "targets": [ + { + "queryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", + "queryType": "table", + "rawQueryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Unique Contributors by Repository", + "transformations": [], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Running total of first-time community contributors over time.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Total Contributors", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 114 + }, + "id": 25, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\ndaily_new AS (\n SELECT \n first_pr_date as date,\n COUNT(*) as new_contributors\n FROM first_contributions\n GROUP BY first_pr_date\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n (SELECT SUM(new_contributors) FROM daily_new dn WHERE dn.date <= d.date) as value\nFROM daily_metrics d\nWHERE CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nGROUP BY d.date\nORDER BY d.date ASC", + "queryType": "table", + "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\ndaily_new AS (\n SELECT \n first_pr_date as date,\n COUNT(*) as new_contributors\n FROM first_contributions\n GROUP BY first_pr_date\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n (SELECT SUM(new_contributors) FROM daily_new dn WHERE dn.date <= d.date) as value\nFROM daily_metrics d\nWHERE CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nGROUP BY d.date\nORDER BY d.date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Cumulative Community Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 300, + "panels": [], + "title": "Adoption", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total all-time downloads across all packages and registries. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 7 + }, + "id": 301, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "Total Downloads (All-Time)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Downloads in the last 7 days across all packages. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 7 + }, + "id": 302, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "Downloads (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total PyPI (Python) downloads all-time. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "yellow", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 7 + }, + "id": 303, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'pypi'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'pypi'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "PyPI Downloads", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total npm (TypeScript) downloads all-time. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 7 + }, + "id": 304, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'npm'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-typescript'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-typescript')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'npm'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "npm Downloads", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Daily download counts by package. PyPI retains 180 days, npm retains 365+ days. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Downloads", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 305, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n pd.downloads as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nORDER BY pd.date, pd.package", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n pd.downloads as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nORDER BY pd.date, pd.package", + "refId": "A", + "timeColumns": [ + "time" + ] + } + ], + "title": "Daily Downloads by Package", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Cumulative downloads over time showing growth trajectory. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Total Downloads", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 306, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) OVER (PARTITION BY pd.package ORDER BY pd.date) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nORDER BY pd.date, pd.package", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) OVER (PARTITION BY pd.package ORDER BY pd.date) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nORDER BY pd.date, pd.package", + "refId": "A", + "timeColumns": [ + "time" + ] + } + ], + "title": "Cumulative Downloads by Package", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Download distribution by registry (PyPI vs npm). Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pypi" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "npm" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 19 + }, + "id": 307, + "options": { + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true, + "values": [ + "value", + "percent" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT pd.registry, SUM(pd.downloads) as count\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY pd.registry", + "queryType": "table", + "rawQueryText": "SELECT pd.registry, SUM(pd.downloads) as count\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY pd.registry", + "refId": "A" + } + ], + "title": "Downloads by Registry", + "transformations": [ + { + "id": "rowsToFields", + "options": { + "mappings": [ + { + "fieldName": "registry", + "handlerKey": "field.name" + }, + { + "fieldName": "count", + "handlerKey": "field.value" + } + ] + } + } + ], + "type": "piechart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Downloads per package for selected time range. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Downloads", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 10, + "x": 6, + "y": 19 + }, + "id": 308, + "options": { + "barRadius": 0.1, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY pd.package\nORDER BY downloads DESC", + "queryType": "table", + "rawQueryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY pd.package\nORDER BY downloads DESC", + "refId": "A" + } + ], + "title": "Downloads by Package", + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Week-over-week download trends by registry. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": true, + "axisLabel": "Downloads", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 19 + }, + "id": 309, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', strftime('%Y-%m-%d', pd.date, 'weekday 0', '-6 days')) as INTEGER) as time,\n pd.registry as metric,\n SUM(pd.downloads) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY strftime('%Y-%W', pd.date), pd.registry\nORDER BY time", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', strftime('%Y-%m-%d', pd.date, 'weekday 0', '-6 days')) as INTEGER) as time,\n pd.registry as metric,\n SUM(pd.downloads) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY strftime('%Y-%W', pd.date), pd.registry\nORDER BY time", + "refId": "A", + "timeColumns": [ + "time" + ] + } + ], + "title": "Weekly Downloads by Registry", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [ + { + "allowCustomValue": false, + "current": { + "text": [ + "agent-builder", + "agent-sop", + "docs", + "sdk-python", + "sdk-typescript", + "tools", + "evals" + ], + "value": [ + "agent-builder", + "agent-sop", + "docs", + "sdk-python", + "sdk-typescript", + "tools", + "evals" + ] + }, + "definition": "SELECT DISTINCT repo FROM daily_metrics", + "description": "", + "includeAll": true, + "multi": true, + "name": "repo", + "options": [], + "query": "SELECT DISTINCT repo FROM daily_metrics", + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30d", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Overview", + "uid": "adj9pgt", + "version": 10 +} \ No newline at end of file diff --git a/community-dashboard/provisioning/dashboards/operations/team.json b/community-dashboard/provisioning/dashboards/operations/team.json new file mode 100644 index 0000000..a3c6589 --- /dev/null +++ b/community-dashboard/provisioning/dashboards/operations/team.json @@ -0,0 +1,641 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 208, + "panels": [], + "title": "Team Performance", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. PRs Authored, Reviews Given, Balance, and Score per team member. Uses team_members table - run 'strands-metrics load-team' to configure.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Score" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "min", + "value": 0 + }, + { + "id": "color", + "value": { + "mode": "continuous-BlYlRd" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Balance" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "orange", + "value": -10 + }, + { + "color": "yellow", + "value": -3 + }, + { + "color": "green", + "value": 3 + }, + { + "color": "blue", + "value": 15 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team Member" + }, + "properties": [ + { + "id": "custom.width", + "value": 150 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PRs Authored" + }, + "properties": [ + { + "id": "custom.width", + "value": 110 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Reviews Given" + }, + "properties": [ + { + "id": "custom.width", + "value": 120 + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 16, + "x": 0, + "y": 1 + }, + "id": 209, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Score" + } + ] + }, + "targets": [ + { + "queryText": "WITH team_prs AS (\n SELECT \n author,\n COUNT(*) as prs_authored\n FROM pull_requests\n WHERE merged_at IS NOT NULL\n AND author IN (SELECT username FROM team_members)\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\nreviews AS (\n SELECT \n author as reviewer,\n COUNT(DISTINCT repo || '-' || pr_number) as reviews_given\n FROM pr_reviews\n WHERE author IN (SELECT username FROM team_members)\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) <= $__to / 1000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n)\nSELECT \n COALESCE(tp.author, r.reviewer) as \"Team Member\",\n COALESCE(tp.prs_authored, 0) as \"PRs Authored\",\n COALESCE(r.reviews_given, 0) as \"Reviews Given\",\n COALESCE(r.reviews_given, 0) - COALESCE(tp.prs_authored, 0) as \"Balance\",\n COALESCE(tp.prs_authored, 0) * 2 + COALESCE(r.reviews_given, 0) as \"Score\"\nFROM team_prs tp\nFULL OUTER JOIN reviews r ON tp.author = r.reviewer\nWHERE COALESCE(tp.prs_authored, 0) + COALESCE(r.reviews_given, 0) > 0\nORDER BY \"Score\" DESC", + "queryType": "table", + "rawQueryText": "WITH team_prs AS (\n SELECT \n author,\n COUNT(*) as prs_authored\n FROM pull_requests\n WHERE merged_at IS NOT NULL\n AND author IN (SELECT username FROM team_members)\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\nreviews AS (\n SELECT \n author as reviewer,\n COUNT(DISTINCT repo || '-' || pr_number) as reviews_given\n FROM pr_reviews\n WHERE author IN (SELECT username FROM team_members)\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) <= $__to / 1000\n AND repo IN (${repo:singlequote})\n GROUP BY author\n)\nSELECT \n COALESCE(tp.author, r.reviewer) as \"Team Member\",\n COALESCE(tp.prs_authored, 0) as \"PRs Authored\",\n COALESCE(r.reviews_given, 0) as \"Reviews Given\",\n COALESCE(r.reviews_given, 0) - COALESCE(tp.prs_authored, 0) as \"Balance\",\n COALESCE(tp.prs_authored, 0) * 2 + COALESCE(r.reviews_given, 0) as \"Score\"\nFROM team_prs tp\nFULL OUTER JOIN reviews r ON tp.author = r.reviewer\nWHERE COALESCE(tp.prs_authored, 0) + COALESCE(r.reviews_given, 0) > 0\nORDER BY \"Score\" DESC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "\ud83d\udcca Team Scorecard", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Git Gladiator = Most PRs. Relentless Reviewer = Most Reviews.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "center", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Category" + }, + "properties": [ + { + "id": "custom.width", + "value": 170 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Leader" + }, + "properties": [ + { + "id": "custom.width", + "value": 130 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 70 + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 210, + "options": { + "cellHeight": "md", + "showHeader": true + }, + "targets": [ + { + "queryText": "SELECT * FROM (\n SELECT '\ud83c\udfc6 Git Gladiator' as \"Category\", author as \"Leader\", COUNT(*) as \"Count\"\n FROM pull_requests\n WHERE merged_at IS NOT NULL\n AND author IN (SELECT username FROM team_members)\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author ORDER BY COUNT(*) DESC LIMIT 1\n)\nUNION ALL\nSELECT * FROM (\n SELECT '\ud83d\udd0d Relentless Reviewer' as \"Category\", author as \"Leader\", COUNT(DISTINCT repo || '-' || pr_number) as \"Count\"\n FROM pr_reviews\n WHERE author IN (SELECT username FROM team_members)\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) <= $__to / 1000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author ORDER BY COUNT(DISTINCT repo || '-' || pr_number) DESC LIMIT 1\n)", + "queryType": "table", + "rawQueryText": "SELECT * FROM (\n SELECT '\ud83c\udfc6 Git Gladiator' as \"Category\", author as \"Leader\", COUNT(*) as \"Count\"\n FROM pull_requests\n WHERE merged_at IS NOT NULL\n AND author IN (SELECT username FROM team_members)\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n AND repo IN (${repo:singlequote})\n GROUP BY author ORDER BY COUNT(*) DESC LIMIT 1\n)\nUNION ALL\nSELECT * FROM (\n SELECT '\ud83d\udd0d Relentless Reviewer' as \"Category\", author as \"Leader\", COUNT(DISTINCT repo || '-' || pr_number) as \"Count\"\n FROM pr_reviews\n WHERE author IN (SELECT username FROM team_members)\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) <= $__to / 1000\n AND repo IN (${repo:singlequote})\n GROUP BY author ORDER BY COUNT(DISTINCT repo || '-' || pr_number) DESC LIMIT 1\n)", + "refId": "A" + } + ], + "title": "\ud83c\udfc5 Category Leaders", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. Weekly (reviews given - PRs authored). Positive = team reviewing more.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": true, + "axisColorMode": "text", + "axisLabel": "Balance", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "area" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 7 + }, + "id": 211, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH weekly_stats AS (\n SELECT \n strftime('%Y-%m-%d', date(merged_at, 'weekday 0', '-6 days')) as week_start,\n COUNT(*) as pr_count,\n 0 as review_count\n FROM pull_requests\n WHERE merged_at IS NOT NULL\n AND author IN (SELECT username FROM team_members)\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY week_start\n \n UNION ALL\n \n SELECT \n strftime('%Y-%m-%d', date(submitted_at, 'weekday 0', '-6 days')) as week_start,\n 0 as pr_count,\n COUNT(DISTINCT repo || '-' || pr_number) as review_count\n FROM pr_reviews\n WHERE author IN (SELECT username FROM team_members)\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY week_start\n)\nSELECT \n CAST(strftime('%s', week_start) as INTEGER) as time,\n 'Review Balance' as metric,\n SUM(review_count) - SUM(pr_count) as value\nFROM weekly_stats\nWHERE CAST(strftime('%s', week_start) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', week_start) as INTEGER) <= $__to / 1000\nGROUP BY week_start\nORDER BY week_start", + "queryType": "table", + "rawQueryText": "WITH weekly_stats AS (\n SELECT \n strftime('%Y-%m-%d', date(merged_at, 'weekday 0', '-6 days')) as week_start,\n COUNT(*) as pr_count,\n 0 as review_count\n FROM pull_requests\n WHERE merged_at IS NOT NULL\n AND author IN (SELECT username FROM team_members)\n AND repo IN (${repo:singlequote})\n GROUP BY week_start\n \n UNION ALL\n \n SELECT \n strftime('%Y-%m-%d', date(submitted_at, 'weekday 0', '-6 days')) as week_start,\n 0 as pr_count,\n COUNT(DISTINCT repo || '-' || pr_number) as review_count\n FROM pr_reviews\n WHERE author IN (SELECT username FROM team_members)\n AND repo IN (${repo:singlequote})\n GROUP BY week_start\n)\nSELECT \n CAST(strftime('%s', week_start) as INTEGER) as time,\n 'Review Balance' as metric,\n SUM(review_count) - SUM(pr_count) as value\nFROM weekly_stats\nWHERE CAST(strftime('%s', week_start) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', week_start) as INTEGER) <= $__to / 1000\nGROUP BY week_start\nORDER BY week_start", + "refId": "A", + "timeColumns": [ + "time" + ] + } + ], + "title": "\ud83d\udcc8 Team Review Balance (Weekly)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. Pie chart of merged PRs by source: Team (from team_members table), Community, Dependabot. Run 'strands-metrics load-team' to configure.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Community" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dependabot" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 13 + }, + "id": 212, + "options": { + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true, + "values": [ + "value", + "percent" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CASE \n WHEN author IN (SELECT username FROM team_members) THEN 'Team'\n WHEN author LIKE '%[bot]%' OR author = 'dependabot' THEN 'Dependabot'\n ELSE 'Community'\n END as category,\n COUNT(*) as count\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\nGROUP BY category", + "queryType": "table", + "rawQueryText": "SELECT \n CASE \n WHEN author IN (SELECT username FROM team_members) THEN 'Team'\n WHEN author LIKE '%[bot]%' OR author = 'dependabot' THEN 'Dependabot'\n ELSE 'Community'\n END as category,\n COUNT(*) as count\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n AND repo IN (${repo:singlequote})\nGROUP BY category", + "refId": "A" + } + ], + "title": "PR Source Breakdown", + "transformations": [ + { + "id": "rowsToFields", + "options": { + "mappings": [ + { + "fieldName": "category", + "handlerKey": "field.name" + }, + { + "fieldName": "count", + "handlerKey": "field.value" + } + ] + } + } + ], + "type": "piechart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. Bar chart of review counts per team member.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Reviews Given", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 13 + }, + "id": 214, + "options": { + "barRadius": 0.1, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n author as reviewer,\n COUNT(DISTINCT repo || '-' || pr_number) as reviews_given\nFROM pr_reviews\nWHERE author IN (SELECT username FROM team_members)\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) <= $__to / 1000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\nGROUP BY author\nORDER BY reviews_given DESC\nLIMIT 10", + "queryType": "table", + "rawQueryText": "SELECT \n author as reviewer,\n COUNT(DISTINCT repo || '-' || pr_number) as reviews_given\nFROM pr_reviews\nWHERE author IN (SELECT username FROM team_members)\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(submitted_at)) as INTEGER) <= $__to / 1000\n AND repo IN (${repo:singlequote})\nGROUP BY author\nORDER BY reviews_given DESC\nLIMIT 10", + "refId": "A" + } + ], + "title": "\ud83d\udd0d Reviews per Team Member", + "type": "barchart" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [ + { + "allowCustomValue": false, + "current": { + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "definition": "SELECT DISTINCT repo FROM daily_metrics", + "includeAll": true, + "multi": true, + "name": "repo", + "options": [], + "query": "SELECT DISTINCT repo FROM daily_metrics", + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30d", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Strands Team", + "uid": "team-perf", + "version": 1 +} \ No newline at end of file diff --git a/community-dashboard/provisioning/dashboards/operations/triage.json b/community-dashboard/provisioning/dashboards/operations/triage.json new file mode 100644 index 0000000..f5d3961 --- /dev/null +++ b/community-dashboard/provisioning/dashboards/operations/triage.json @@ -0,0 +1,1214 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 0, + "links": [], + "panels": [ + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current open PRs. Point-in-time snapshot - not affected by date range. ", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hideFrom.viz", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Status" + }, + "properties": [ + { + "id": "custom.width", + "value": 118 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Days Open" + }, + "properties": [ + { + "id": "custom.width", + "value": 87 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Author" + }, + "properties": [ + { + "id": "custom.width", + "value": 148 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Repo" + }, + "properties": [ + { + "id": "custom.width", + "value": 161 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Labels" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Days Since Activity" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 22, + "x": 1, + "y": 0 + }, + "id": 1, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Days Open" + } + ] + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "queryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n COALESCE(\n (SELECT GROUP_CONCAT(json_extract(value, '$.name'), ', ') \n FROM json_each(json_extract(p.data, '$.labels'))), \n ''\n ) as \"Labels\",\n CASE \n WHEN r.state = 'APPROVED' THEN '✅ Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN '🔄 Changes Requested' \n ELSE '👀 Needs Review' \n END as \"Status\", \n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\",\n CAST((julianday('now') - julianday(p.updated_at)) as INTEGER) as \"Days Since Activity\"\nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\nORDER BY \"Days Open\" DESC", + "queryType": "table", + "rawQueryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n COALESCE(\n (SELECT GROUP_CONCAT(json_extract(value, '$.name'), ', ') \n FROM json_each(json_extract(p.data, '$.labels'))), \n ''\n ) as \"Labels\",\n CASE \n WHEN r.state = 'APPROVED' THEN '✅ Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN '🔄 Changes Requested' \n ELSE '👀 Needs Review' \n END as \"Status\", \n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\",\n CAST((julianday('now') - julianday(p.updated_at)) as INTEGER) as \"Days Since Activity\"\nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN (${repo:singlequote})\nORDER BY \"Days Open\" DESC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Team PRs", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current open PRs. Point-in-time snapshot - not affected by date range. ", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hideFrom.viz", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Status" + }, + "properties": [ + { + "id": "custom.width", + "value": 118 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Days Open" + }, + "properties": [ + { + "id": "custom.width", + "value": 87 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Author" + }, + "properties": [ + { + "id": "custom.width", + "value": 148 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Repo" + }, + "properties": [ + { + "id": "custom.width", + "value": 161 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Labels" + }, + "properties": [ + { + "id": "custom.width", + "value": 150 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "New Contributor" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Days Since Activity" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 22, + "x": 1, + "y": 8 + }, + "id": 2, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Days Open" + } + ] + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "queryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n COALESCE(\n (SELECT GROUP_CONCAT(json_extract(value, '$.name'), ', ') \n FROM json_each(json_extract(p.data, '$.labels'))), \n ''\n ) as \"Labels\",\n CASE \n WHEN r.state = 'APPROVED' THEN '✅ Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN '🔄 Changes Requested' \n ELSE '👀 Needs Review' \n END as \"Status\",\n CASE \n WHEN NOT EXISTS (\n SELECT 1 FROM pull_requests p2 \n WHERE p2.author = p.author \n AND p2.merged_at IS NOT NULL \n AND p2.created_at < p.created_at\n ) THEN '🆕 First PR!'\n ELSE ''\n END as \"New Contributor\",\n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\",\n CAST((julianday('now') - julianday(p.updated_at)) as INTEGER) as \"Days Since Activity\"\nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\nORDER BY \"Days Open\" DESC", + "queryType": "table", + "rawQueryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n COALESCE(\n (SELECT GROUP_CONCAT(json_extract(value, '$.name'), ', ') \n FROM json_each(json_extract(p.data, '$.labels'))), \n ''\n ) as \"Labels\",\n CASE \n WHEN r.state = 'APPROVED' THEN '✅ Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN '🔄 Changes Requested' \n ELSE '👀 Needs Review' \n END as \"Status\",\n CASE \n WHEN NOT EXISTS (\n SELECT 1 FROM pull_requests p2 \n WHERE p2.author = p.author \n AND p2.merged_at IS NOT NULL \n AND p2.created_at < p.created_at\n ) THEN '🆕 First PR!'\n ELSE ''\n END as \"New Contributor\",\n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\",\n CAST((julianday('now') - julianday(p.updated_at)) as INTEGER) as \"Days Since Activity\"\nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN (${repo:singlequote})\nORDER BY \"Days Open\" DESC", + "refId": "A" + } + ], + "title": "Community PRs", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current open issues without a milestone. Point-in-time snapshot - not affected by date range.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hideFrom.viz", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Comments" + }, + "properties": [ + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Repo" + }, + "properties": [ + { + "id": "custom.width", + "value": 160 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Labels" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Days Open" + }, + "properties": [ + { + "id": "custom.width", + "value": 80 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 22, + "x": 1, + "y": 16 + }, + "id": 3, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Days Open" + } + ] + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n repo as \"Repo\", \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n COALESCE(\n (SELECT GROUP_CONCAT(json_extract(value, '$.name'), ', ') \n FROM json_each(json_extract(data, '$.labels'))), \n ''\n ) as \"Labels\",\n json_extract(data, '$.comments') as \"Comments\",\n CAST((julianday('now') - julianday(created_at)) as INTEGER) as \"Days Open\"\nFROM issues \nWHERE state = 'open' AND json_extract(data, '$.milestone') IS NULL AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\nORDER BY \"Days Open\" DESC", + "queryType": "table", + "rawQueryText": "SELECT \n repo as \"Repo\", \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n COALESCE(\n (SELECT GROUP_CONCAT(json_extract(value, '$.name'), ', ') \n FROM json_each(json_extract(data, '$.labels'))), \n ''\n ) as \"Labels\",\n json_extract(data, '$.comments') as \"Comments\",\n CAST((julianday('now') - julianday(created_at)) as INTEGER) as \"Days Open\"\nFROM issues \nWHERE state = 'open' AND json_extract(data, '$.milestone') IS NULL AND repo IN (${repo:singlequote})\nORDER BY \"Days Open\" DESC", + "refId": "A" + } + ], + "title": "Untriaged Issues (No Milestone)", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current open issues sorted by upvotes. Point-in-time snapshot - not affected by date range.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hideFrom.viz", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Upvotes" + }, + "properties": [ + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Repo" + }, + "properties": [ + { + "id": "custom.width", + "value": 120 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 1, + "y": 24 + }, + "id": 4, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Upvotes" + } + ] + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n repo as \"Repo\",\n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.reactions.\"+1\"') as \"Upvotes\" \nFROM issues WHERE state = 'open' AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\nORDER BY \"Upvotes\" DESC LIMIT 20", + "queryType": "table", + "rawQueryText": "SELECT \n repo as \"Repo\",\n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.reactions.\"+1\"') as \"Upvotes\" \nFROM issues WHERE state = 'open' AND repo IN (${repo:singlequote})\nORDER BY \"Upvotes\" DESC LIMIT 20", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Top Upvoted Issues", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current open issues sorted by comment count. Point-in-time snapshot - not affected by date range.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hideFrom.viz", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Comments" + }, + "properties": [ + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Repo" + }, + "properties": [ + { + "id": "custom.width", + "value": 120 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 10, + "x": 13, + "y": 24 + }, + "id": 5, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Comments" + } + ] + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n repo as \"Repo\",\n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.comments') as \"Comments\" \nFROM issues WHERE state = 'open' AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\nORDER BY \"Comments\" DESC LIMIT 20", + "queryType": "table", + "rawQueryText": "SELECT \n repo as \"Repo\",\n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.comments') as \"Comments\" \nFROM issues WHERE state = 'open' AND repo IN (${repo:singlequote})\nORDER BY \"Comments\" DESC LIMIT 20", + "refId": "A" + } + ], + "title": "Most Discussed Issues", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current open PRs with no activity in 7+ days. Point-in-time snapshot.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 4.95 + }, + { + "color": "red", + "value": 15.0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Days Stale" + }, + "properties": [ + { + "id": "custom.width", + "value": 90 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Repo" + }, + "properties": [ + { + "id": "custom.width", + "value": 140 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Author" + }, + "properties": [ + { + "id": "custom.width", + "value": 130 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Type" + }, + "properties": [ + { + "id": "custom.width", + "value": 90 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 22, + "x": 1, + "y": 32 + }, + "id": 6, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Days Stale" + } + ] + }, + "targets": [ + { + "queryText": "SELECT \n p.repo as \"Repo\",\n p.author as \"Author\",\n CASE \n WHEN json_extract(p.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 'Team'\n ELSE 'Community'\n END as \"Type\",\n p.title as \"Title\",\n json_extract(p.data, '$.html_url') as \"URL\",\n CAST((julianday('now') - julianday(p.updated_at)) as INTEGER) as \"Days Stale\"\nFROM pull_requests p\nWHERE p.state = 'open'\n AND date(p.updated_at) < date('now', '-7 days')\n AND p.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\nORDER BY \"Days Stale\" DESC", + "queryType": "table", + "rawQueryText": "SELECT \n p.repo as \"Repo\",\n p.author as \"Author\",\n CASE \n WHEN json_extract(p.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 'Team'\n ELSE 'Community'\n END as \"Type\",\n p.title as \"Title\",\n json_extract(p.data, '$.html_url') as \"URL\",\n CAST((julianday('now') - julianday(p.updated_at)) as INTEGER) as \"Days Stale\"\nFROM pull_requests p\nWHERE p.state = 'open'\n AND date(p.updated_at) < date('now', '-7 days')\n AND p.repo IN (${repo:singlequote})\nORDER BY \"Days Stale\" DESC", + "refId": "A" + } + ], + "title": "⚠️ Stale PRs (7d+ No Activity)", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current open PRs from first-time contributors. Point-in-time snapshot - not affected by date range.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Days Open" + }, + "properties": [ + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Repo" + }, + "properties": [ + { + "id": "custom.width", + "value": 140 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Author" + }, + "properties": [ + { + "id": "custom.width", + "value": 130 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Status" + }, + "properties": [ + { + "id": "custom.width", + "value": 130 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 22, + "x": 1, + "y": 40 + }, + "id": 7, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Days Open" + } + ] + }, + "targets": [ + { + "queryText": "SELECT \n p.repo as \"Repo\",\n p.author as \"Author\",\n p.title as \"Title\",\n json_extract(p.data, '$.html_url') as \"URL\",\n CASE \n WHEN r.state = 'APPROVED' THEN '✅ Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN '🔄 Changes Requested' \n ELSE '👀 Needs Review' \n END as \"Status\",\n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\"\nFROM pull_requests p\nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number\nWHERE p.state = 'open'\n AND json_extract(p.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND NOT EXISTS (\n SELECT 1 FROM pull_requests p2 \n WHERE p2.author = p.author \n AND p2.merged_at IS NOT NULL \n AND p2.created_at < p.created_at\n )\n AND p.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\nORDER BY \"Days Open\" DESC", + "queryType": "table", + "rawQueryText": "SELECT \n p.repo as \"Repo\",\n p.author as \"Author\",\n p.title as \"Title\",\n json_extract(p.data, '$.html_url') as \"URL\",\n CASE \n WHEN r.state = 'APPROVED' THEN '✅ Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN '🔄 Changes Requested' \n ELSE '👀 Needs Review' \n END as \"Status\",\n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\"\nFROM pull_requests p\nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number\nWHERE p.state = 'open'\n AND json_extract(p.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND NOT EXISTS (\n SELECT 1 FROM pull_requests p2 \n WHERE p2.author = p.author \n AND p2.merged_at IS NOT NULL \n AND p2.created_at < p.created_at\n )\n AND p.repo IN (${repo:singlequote})\nORDER BY \"Days Open\" DESC", + "refId": "A" + } + ], + "title": "🌟 First-Time Contributors (Needs Welcome!)", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current open Dependabot PRs. Point-in-time snapshot - not affected by date range.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "footer": { + "reducers": [] + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange", + "value": 0 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Open on GitHub", + "url": "${__data.fields.URL}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "URL" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Days Open" + }, + "properties": [ + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Repo" + }, + "properties": [ + { + "id": "custom.width", + "value": 140 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 22, + "x": 1, + "y": 48 + }, + "id": 8, + "options": { + "cellHeight": "sm", + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Days Open" + } + ] + }, + "targets": [ + { + "queryText": "SELECT \n p.repo as \"Repo\",\n p.title as \"Title\",\n json_extract(p.data, '$.html_url') as \"URL\",\n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\"\nFROM pull_requests p\nWHERE p.state = 'open'\n AND (p.author LIKE '%[bot]%' OR p.author = 'dependabot')\n AND p.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\nORDER BY \"Days Open\" DESC", + "queryType": "table", + "rawQueryText": "SELECT \n p.repo as \"Repo\",\n p.title as \"Title\",\n json_extract(p.data, '$.html_url') as \"URL\",\n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\"\nFROM pull_requests p\nWHERE p.state = 'open'\n AND (p.author LIKE '%[bot]%' OR p.author = 'dependabot')\n AND p.repo IN (${repo:singlequote})\nORDER BY \"Days Open\" DESC", + "refId": "A" + } + ], + "title": "🤖 Dependabot PRs", + "type": "table" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [ + { + "allowCustomValue": false, + "current": { + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "definition": "SELECT DISTINCT repo FROM daily_metrics", + "includeAll": true, + "multi": true, + "name": "repo", + "options": [], + "query": "SELECT DISTINCT repo FROM daily_metrics", + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30d", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Strands Triage", + "uid": "advqxqk", + "version": 7 +} \ No newline at end of file diff --git a/community-dashboard/provisioning/dashboards/sdks/evals.json b/community-dashboard/provisioning/dashboards/sdks/evals.json new file mode 100644 index 0000000..7c5ddca --- /dev/null +++ b/community-dashboard/provisioning/dashboards/sdks/evals.json @@ -0,0 +1,11853 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 200, + "panels": [], + "title": "Key Metrics", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current count of open pull requests. This is a point-in-time snapshot, not affected by date range.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 1 + }, + "id": 201, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value FROM pull_requests WHERE state = 'open' AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value FROM pull_requests WHERE state = 'open' AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Open PRs (Current)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Average hours from PR open to merge. Fixed 14-day lookback - does not change with date picker. Goal threshold shown on related charts.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 18.0 + }, + { + "color": "red", + "value": 24.0 + } + ] + }, + "unit": "h" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 1 + }, + "id": 202, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-14 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-14 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'avg_merge_time_hours'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'avg_merge_time_hours'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Avg Merge Time (14d)", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Percentage of merged PRs from community contributors. Fixed 30-day lookback - does not change with date picker. Goal threshold shown on related charts.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 14.0 + }, + { + "color": "green", + "value": 20.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 203, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-30 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-30 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Community PR % (30d)", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Unique PR authors in the last 7 days. Fixed lookback - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 1 + }, + "id": 204, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(DISTINCT author) as value\nFROM pull_requests \nWHERE date(created_at) >= date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(DISTINCT author) as value\nFROM pull_requests \nWHERE date(created_at) >= date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Active Contributors (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "PRs merged in the last 7 days. Fixed lookback - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 1 + }, + "id": 205, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Merged (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Open PRs with no activity in 7+ days. Fixed threshold - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 4.95 + }, + { + "color": "red", + "value": 15.0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 1 + }, + "id": 206, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE state = 'open'\n AND date(updated_at) < date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE state = 'open'\n AND date(updated_at) < date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Stale PRs (7d+)", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 100, + "panels": [], + "title": "Volume", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 101, + "panels": [], + "title": "Speed", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 61 + }, + "id": 102, + "panels": [], + "title": "Quality", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 78 + }, + "id": 103, + "panels": [], + "title": "Community", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current count of open pull requests across selected repositories. Point-in-time snapshot.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Open PRs (Current)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current cumulative count of GitHub stars. Point-in-time snapshot.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 79 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Stars (Current)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Count of unique community contributors who created PRs in the rolling 7-day window ending on each date.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 79 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "queryType": "table", + "rawQueryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Weekly Active Community Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 30-day rolling average percentage of merged PRs from community contributors.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (20%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 87 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Community PR Share (30-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of PRs closed without being merged.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 87 + }, + "id": 9, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Rejected PRs (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of PRs that waited >48 hours for first review.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 53 + }, + "id": 19, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(first_review_at)) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(first_review_at), repo\nORDER BY first_review_at ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(first_review_at)) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(first_review_at), repo\nORDER BY first_review_at ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Slow Reviews (>48h Wait)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 7-day rolling average of CI failure rate.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 22.5 + }, + { + "color": "red", + "value": 30.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (30%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 62 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "CI Failure Rate (7-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 7-day rolling average of lines changed per day. Days >10k lines filtered out.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 70 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Code Churn (7-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 30-day rolling average of (PRs merged / PRs opened) × 100%.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 42.0 + }, + { + "color": "green", + "value": 60.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (60%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 62 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN (${repo:singlequote})\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "PR Acceptance Rate (30-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Week-over-week change in open PR count.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": true, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 70 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Backlog Growth (WoW)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of new GitHub Issues opened.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 2, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Opened (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of GitHub Issues closed.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 3, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Closed (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of pull requests merged.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 1, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PRs Merged (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Average hours until first response on issues/PRs.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 18.0 + }, + { + "color": "red", + "value": 24.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (24h)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 53 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND avg_issue_resolution_time > 0\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND avg_issue_resolution_time > 0\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Time to First Response", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 14-day rolling average hours from PR open to merge, by contributor type.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 252.0 + }, + { + "color": "red", + "value": 336.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (14d)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 45 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Cycle Time (14-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 14-day rolling average hours until first PR review, by contributor type.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 54.0 + }, + { + "color": "red", + "value": 72.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (72h)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 45 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Time to First Review (14-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 95 + }, + "id": 104, + "panels": [], + "title": "Contributor Insights", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of first-time vs returning contributors.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "New Contributors" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Returning Contributors" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 96 + }, + "id": 21, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(created_at), author\n)\nSELECT \n CAST(strftime('%s', dc.pr_date) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY dc.pr_date, metric\nORDER BY dc.pr_date ASC", + "queryType": "table", + "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY date(created_at), author\n)\nSELECT \n CAST(strftime('%s', dc.pr_date) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY dc.pr_date, metric\nORDER BY dc.pr_date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "New vs Returning Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Percentage of contributors from 30-60 days ago who returned in last 30 days.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Retention %", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 17.5 + }, + { + "color": "green", + "value": 25.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Goal (25%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 96 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "mean", + "last" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH date_series AS (\n SELECT DISTINCT date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "queryType": "table", + "rawQueryText": "WITH date_series AS (\n SELECT DISTINCT date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Contributor Retention Rate", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Leaderboard of community contributors by PR count.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pr_count" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "min", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "repos" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 104 + }, + "id": 23, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "pr_count" + } + ] + }, + "targets": [ + { + "queryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", + "queryType": "table", + "rawQueryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Top Community Contributors", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Community contributor count per repository.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 104 + }, + "id": 24, + "options": { + "barRadius": 0.1, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "targets": [ + { + "queryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", + "queryType": "table", + "rawQueryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Unique Contributors by Repository", + "transformations": [], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Running total of first-time community contributors over time.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Total Contributors", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 114 + }, + "id": 25, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\ndaily_new AS (\n SELECT \n first_pr_date as date,\n COUNT(*) as new_contributors\n FROM first_contributions\n GROUP BY first_pr_date\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n (SELECT SUM(new_contributors) FROM daily_new dn WHERE dn.date <= d.date) as value\nFROM daily_metrics d\nWHERE CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nGROUP BY d.date\nORDER BY d.date ASC", + "queryType": "table", + "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\ndaily_new AS (\n SELECT \n first_pr_date as date,\n COUNT(*) as new_contributors\n FROM first_contributions\n GROUP BY first_pr_date\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n (SELECT SUM(new_contributors) FROM daily_new dn WHERE dn.date <= d.date) as value\nFROM daily_metrics d\nWHERE CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nGROUP BY d.date\nORDER BY d.date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Cumulative Community Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 300, + "panels": [], + "title": "Adoption", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total all-time downloads across all packages and registries. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 7 + }, + "id": 301, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "Total Downloads (All-Time)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Downloads in the last 7 days across all packages. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 7 + }, + "id": 302, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "Downloads (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total PyPI (Python) downloads all-time. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "yellow", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 7 + }, + "id": 303, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'pypi'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'pypi'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "PyPI Downloads", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Daily download counts by package. PyPI retains 180 days, npm retains 365+ days. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Downloads", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 305, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n pd.downloads as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nORDER BY pd.date, pd.package", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n pd.downloads as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nORDER BY pd.date, pd.package", + "refId": "A", + "timeColumns": [ + "time" + ] + } + ], + "title": "Daily Downloads by Package", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Cumulative downloads over time showing growth trajectory. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Total Downloads", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 306, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) OVER (PARTITION BY pd.package ORDER BY pd.date) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nORDER BY pd.date, pd.package", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) OVER (PARTITION BY pd.package ORDER BY pd.date) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nORDER BY pd.date, pd.package", + "refId": "A", + "timeColumns": [ + "time" + ] + } + ], + "title": "Cumulative Downloads by Package", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Downloads per package for selected time range. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Downloads", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 308, + "options": { + "barRadius": 0.1, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY pd.package\nORDER BY downloads DESC", + "queryType": "table", + "rawQueryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY pd.package\nORDER BY downloads DESC", + "refId": "A" + } + ], + "title": "Downloads by Package", + "type": "barchart" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [ + { + "allowCustomValue": false, + "current": { + "text": [ + "evals" + ], + "value": [ + "evals" + ] + }, + "definition": "SELECT DISTINCT repo FROM daily_metrics", + "description": "", + "includeAll": true, + "multi": true, + "name": "repo", + "options": [], + "query": "SELECT DISTINCT repo FROM daily_metrics", + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30d", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Evals", + "uid": "evals", + "version": 10 +} \ No newline at end of file diff --git a/community-dashboard/provisioning/dashboards/sdks/python-sdk.json b/community-dashboard/provisioning/dashboards/sdks/python-sdk.json new file mode 100644 index 0000000..9b5b8f5 --- /dev/null +++ b/community-dashboard/provisioning/dashboards/sdks/python-sdk.json @@ -0,0 +1,11855 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 200, + "panels": [], + "title": "Key Metrics", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current count of open pull requests. This is a point-in-time snapshot, not affected by date range.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 1 + }, + "id": 201, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value FROM pull_requests WHERE state = 'open' AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value FROM pull_requests WHERE state = 'open' AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Open PRs (Current)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Average hours from PR open to merge. Fixed 14-day lookback - does not change with date picker. Goal threshold shown on related charts.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 18.0 + }, + { + "color": "red", + "value": 24.0 + } + ] + }, + "unit": "h" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 1 + }, + "id": 202, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-14 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-14 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'avg_merge_time_hours'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'avg_merge_time_hours'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Avg Merge Time (14d)", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Percentage of merged PRs from community contributors. Fixed 30-day lookback - does not change with date picker. Goal threshold shown on related charts.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 14.0 + }, + { + "color": "green", + "value": 20.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 203, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-30 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-30 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Community PR % (30d)", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Unique PR authors in the last 7 days. Fixed lookback - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 1 + }, + "id": 204, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(DISTINCT author) as value\nFROM pull_requests \nWHERE date(created_at) >= date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(DISTINCT author) as value\nFROM pull_requests \nWHERE date(created_at) >= date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Active Contributors (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "PRs merged in the last 7 days. Fixed lookback - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 1 + }, + "id": 205, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Merged (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Open PRs with no activity in 7+ days. Fixed threshold - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 4.95 + }, + { + "color": "red", + "value": 15.0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 1 + }, + "id": 206, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE state = 'open'\n AND date(updated_at) < date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE state = 'open'\n AND date(updated_at) < date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Stale PRs (7d+)", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 100, + "panels": [], + "title": "Volume", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 101, + "panels": [], + "title": "Speed", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 61 + }, + "id": 102, + "panels": [], + "title": "Quality", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 78 + }, + "id": 103, + "panels": [], + "title": "Community", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current count of open pull requests across selected repositories. Point-in-time snapshot.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Open PRs (Current)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current cumulative count of GitHub stars. Point-in-time snapshot.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 79 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Stars (Current)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Count of unique community contributors who created PRs in the rolling 7-day window ending on each date.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 79 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "queryType": "table", + "rawQueryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Weekly Active Community Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 30-day rolling average percentage of merged PRs from community contributors.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (20%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 87 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Community PR Share (30-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of PRs closed without being merged.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 87 + }, + "id": 9, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Rejected PRs (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of PRs that waited >48 hours for first review.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 53 + }, + "id": 19, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(first_review_at)) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(first_review_at), repo\nORDER BY first_review_at ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(first_review_at)) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(first_review_at), repo\nORDER BY first_review_at ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Slow Reviews (>48h Wait)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 7-day rolling average of CI failure rate.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 22.5 + }, + { + "color": "red", + "value": 30.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (30%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 62 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "CI Failure Rate (7-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 7-day rolling average of lines changed per day. Days >10k lines filtered out.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 70 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Code Churn (7-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 30-day rolling average of (PRs merged / PRs opened) × 100%.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 42.0 + }, + { + "color": "green", + "value": 60.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (60%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 62 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN (${repo:singlequote})\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "PR Acceptance Rate (30-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Week-over-week change in open PR count.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": true, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 70 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Backlog Growth (WoW)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of new GitHub Issues opened.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 2, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Opened (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of GitHub Issues closed.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 3, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Closed (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of pull requests merged.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 1, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PRs Merged (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Average hours until first response on issues/PRs.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 18.0 + }, + { + "color": "red", + "value": 24.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (24h)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 53 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND avg_issue_resolution_time > 0\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND avg_issue_resolution_time > 0\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Time to First Response", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 14-day rolling average hours from PR open to merge, by contributor type.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 252.0 + }, + { + "color": "red", + "value": 336.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (14d)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 45 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Cycle Time (14-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 14-day rolling average hours until first PR review, by contributor type.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 54.0 + }, + { + "color": "red", + "value": 72.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (72h)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 45 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Time to First Review (14-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 95 + }, + "id": 104, + "panels": [], + "title": "Contributor Insights", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of first-time vs returning contributors.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "New Contributors" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Returning Contributors" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 96 + }, + "id": 21, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(created_at), author\n)\nSELECT \n CAST(strftime('%s', dc.pr_date) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY dc.pr_date, metric\nORDER BY dc.pr_date ASC", + "queryType": "table", + "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY date(created_at), author\n)\nSELECT \n CAST(strftime('%s', dc.pr_date) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY dc.pr_date, metric\nORDER BY dc.pr_date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "New vs Returning Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Percentage of contributors from 30-60 days ago who returned in last 30 days.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Retention %", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 17.5 + }, + { + "color": "green", + "value": 25.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Goal (25%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 96 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "mean", + "last" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH date_series AS (\n SELECT DISTINCT date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "queryType": "table", + "rawQueryText": "WITH date_series AS (\n SELECT DISTINCT date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Contributor Retention Rate", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Leaderboard of community contributors by PR count.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pr_count" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "min", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "repos" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 104 + }, + "id": 23, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "pr_count" + } + ] + }, + "targets": [ + { + "queryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", + "queryType": "table", + "rawQueryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Top Community Contributors", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Community contributor count per repository.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 104 + }, + "id": 24, + "options": { + "barRadius": 0.1, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "targets": [ + { + "queryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", + "queryType": "table", + "rawQueryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Unique Contributors by Repository", + "transformations": [], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Running total of first-time community contributors over time.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Total Contributors", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 114 + }, + "id": 25, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\ndaily_new AS (\n SELECT \n first_pr_date as date,\n COUNT(*) as new_contributors\n FROM first_contributions\n GROUP BY first_pr_date\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n (SELECT SUM(new_contributors) FROM daily_new dn WHERE dn.date <= d.date) as value\nFROM daily_metrics d\nWHERE CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nGROUP BY d.date\nORDER BY d.date ASC", + "queryType": "table", + "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\ndaily_new AS (\n SELECT \n first_pr_date as date,\n COUNT(*) as new_contributors\n FROM first_contributions\n GROUP BY first_pr_date\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n (SELECT SUM(new_contributors) FROM daily_new dn WHERE dn.date <= d.date) as value\nFROM daily_metrics d\nWHERE CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nGROUP BY d.date\nORDER BY d.date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Cumulative Community Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 300, + "panels": [], + "title": "Adoption", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total all-time downloads across all packages and registries. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 7 + }, + "id": 301, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "Total Downloads (All-Time)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Downloads in the last 7 days across all packages. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 7 + }, + "id": 302, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "Downloads (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total PyPI (Python) downloads all-time. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "yellow", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 7 + }, + "id": 303, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'pypi'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'pypi'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "PyPI Downloads", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Daily download counts by package. PyPI retains 180 days, npm retains 365+ days. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Downloads", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 305, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n pd.downloads as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nORDER BY pd.date, pd.package", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n pd.downloads as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nORDER BY pd.date, pd.package", + "refId": "A", + "timeColumns": [ + "time" + ] + } + ], + "title": "Daily Downloads by Package", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Cumulative downloads over time showing growth trajectory. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Total Downloads", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 306, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) OVER (PARTITION BY pd.package ORDER BY pd.date) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nORDER BY pd.date, pd.package", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) OVER (PARTITION BY pd.package ORDER BY pd.date) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nORDER BY pd.date, pd.package", + "refId": "A", + "timeColumns": [ + "time" + ] + } + ], + "title": "Cumulative Downloads by Package", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Downloads per package for selected time range. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Downloads", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 308, + "options": { + "barRadius": 0.1, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY pd.package\nORDER BY downloads DESC", + "queryType": "table", + "rawQueryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY pd.package\nORDER BY downloads DESC", + "refId": "A" + } + ], + "title": "Downloads by Package", + "type": "barchart" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [ + { + "allowCustomValue": false, + "current": { + "text": [ + "sdk-python", + "tools" + ], + "value": [ + "sdk-python", + "tools" + ] + }, + "definition": "SELECT DISTINCT repo FROM daily_metrics", + "description": "", + "includeAll": true, + "multi": true, + "name": "repo", + "options": [], + "query": "SELECT DISTINCT repo FROM daily_metrics", + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30d", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Python SDK", + "uid": "python-sdk", + "version": 10 +} \ No newline at end of file diff --git a/community-dashboard/provisioning/dashboards/sdks/typescript-sdk.json b/community-dashboard/provisioning/dashboards/sdks/typescript-sdk.json new file mode 100644 index 0000000..2477d31 --- /dev/null +++ b/community-dashboard/provisioning/dashboards/sdks/typescript-sdk.json @@ -0,0 +1,11853 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 200, + "panels": [], + "title": "Key Metrics", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current count of open pull requests. This is a point-in-time snapshot, not affected by date range.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 1 + }, + "id": 201, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value FROM pull_requests WHERE state = 'open' AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value FROM pull_requests WHERE state = 'open' AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Open PRs (Current)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Average hours from PR open to merge. Fixed 14-day lookback - does not change with date picker. Goal threshold shown on related charts.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 18.0 + }, + { + "color": "red", + "value": 24.0 + } + ] + }, + "unit": "h" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 1 + }, + "id": 202, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-14 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT ROUND(AVG((julianday(merged_at) - julianday(created_at)) * 24), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-14 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'avg_merge_time_hours'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'avg_merge_time_hours'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Avg Merge Time (14d)", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Percentage of merged PRs from community contributors. Fixed 30-day lookback - does not change with date picker. Goal threshold shown on related charts.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 14.0 + }, + { + "color": "green", + "value": 20.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 203, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-30 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT ROUND(100.0 * SUM(CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') THEN 1 ELSE 0 END) / COUNT(*), 1) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-30 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Community PR % (30d)", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Unique PR authors in the last 7 days. Fixed lookback - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 1 + }, + "id": 204, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(DISTINCT author) as value\nFROM pull_requests \nWHERE date(created_at) >= date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(DISTINCT author) as value\nFROM pull_requests \nWHERE date(created_at) >= date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Active Contributors (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "PRs merged in the last 7 days. Fixed lookback - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 1 + }, + "id": 205, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE merged_at IS NOT NULL \n AND date(merged_at) >= date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Merged (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Open PRs with no activity in 7+ days. Fixed threshold - does not change with date picker.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 4.95 + }, + { + "color": "red", + "value": 15.0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 1 + }, + "id": 206, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "queryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE state = 'open'\n AND date(updated_at) < date('now', '-7 days')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value\nFROM pull_requests \nWHERE state = 'open'\n AND date(updated_at) < date('now', '-7 days')\n AND repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Stale PRs (7d+)", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 100, + "panels": [], + "title": "Volume", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 101, + "panels": [], + "title": "Speed", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 61 + }, + "id": 102, + "panels": [], + "title": "Quality", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 78 + }, + "id": 103, + "panels": [], + "title": "Community", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current count of open pull requests across selected repositories. Point-in-time snapshot.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Open PRs (Current)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current cumulative count of GitHub stars. Point-in-time snapshot.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 79 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Total Stars (Current)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Count of unique community contributors who created PRs in the rolling 7-day window ending on each date.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 79 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "queryType": "table", + "rawQueryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Weekly Active Community Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 30-day rolling average percentage of merged PRs from community contributors.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (20%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 87 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Community PR Share (30-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of PRs closed without being merged.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 87 + }, + "id": 9, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Rejected PRs (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of PRs that waited >48 hours for first review.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 53 + }, + "id": 19, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(first_review_at)) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(first_review_at), repo\nORDER BY first_review_at ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(first_review_at)) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(first_review_at), repo\nORDER BY first_review_at ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Slow Reviews (>48h Wait)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 7-day rolling average of CI failure rate.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 22.5 + }, + { + "color": "red", + "value": 30.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (30%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 62 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "CI Failure Rate (7-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 7-day rolling average of lines changed per day. Days >10k lines filtered out.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 70 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Code Churn (7-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 30-day rolling average of (PRs merged / PRs opened) × 100%.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 42.0 + }, + { + "color": "green", + "value": 60.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (60%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 62 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN (${repo:singlequote})\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "PR Acceptance Rate (30-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Week-over-week change in open PR count.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": true, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 70 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Backlog Growth (WoW)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of new GitHub Issues opened.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 2, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Opened (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of GitHub Issues closed.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 3, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Closed (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of pull requests merged.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 1, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PRs Merged (Daily)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Average hours until first response on issues/PRs.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 18.0 + }, + { + "color": "red", + "value": 24.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (24h)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 53 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND avg_issue_resolution_time > 0\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND avg_issue_resolution_time > 0\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Time to First Response", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 14-day rolling average hours from PR open to merge, by contributor type.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 252.0 + }, + { + "color": "red", + "value": 336.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (14d)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 45 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Cycle Time (14-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. 14-day rolling average hours until first PR review, by contributor type.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 54.0 + }, + { + "color": "red", + "value": 72.0 + } + ] + }, + "unit": "h" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Goal (72h)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 45 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Time to First Review (14-Day Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 95 + }, + "id": 104, + "panels": [], + "title": "Contributor Insights", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Daily count of first-time vs returning contributors.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "New Contributors" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Returning Contributors" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 96 + }, + "id": 21, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(created_at), author\n)\nSELECT \n CAST(strftime('%s', dc.pr_date) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY dc.pr_date, metric\nORDER BY dc.pr_date ASC", + "queryType": "table", + "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY date(created_at), author\n)\nSELECT \n CAST(strftime('%s', dc.pr_date) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY dc.pr_date, metric\nORDER BY dc.pr_date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "New vs Returning Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Percentage of contributors from 30-60 days ago who returned in last 30 days.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Retention %", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 17.5 + }, + { + "color": "green", + "value": 25.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Goal (25%)" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 96 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "mean", + "last" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH date_series AS (\n SELECT DISTINCT date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "queryType": "table", + "rawQueryText": "WITH date_series AS (\n SELECT DISTINCT date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'", + "queryType": "table", + "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'", + "refId": "Goal", + "timeColumns": [ + "time" + ] + } + ], + "title": "Contributor Retention Rate", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Leaderboard of community contributors by PR count.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pr_count" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "min", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "repos" + }, + "properties": [ + { + "id": "custom.width", + "value": 300 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 104 + }, + "id": 23, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "pr_count" + } + ] + }, + "targets": [ + { + "queryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", + "queryType": "table", + "rawQueryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Top Community Contributors", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Community contributor count per repository.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 104 + }, + "id": 24, + "options": { + "barRadius": 0.1, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 + }, + "targets": [ + { + "queryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", + "queryType": "table", + "rawQueryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Unique Contributors by Repository", + "transformations": [], + "type": "barchart" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "⏱️ Follows date range. Running total of first-time community contributors over time.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Total Contributors", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 114 + }, + "id": 25, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\ndaily_new AS (\n SELECT \n first_pr_date as date,\n COUNT(*) as new_contributors\n FROM first_contributions\n GROUP BY first_pr_date\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n (SELECT SUM(new_contributors) FROM daily_new dn WHERE dn.date <= d.date) as value\nFROM daily_metrics d\nWHERE CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nGROUP BY d.date\nORDER BY d.date ASC", + "queryType": "table", + "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\ndaily_new AS (\n SELECT \n first_pr_date as date,\n COUNT(*) as new_contributors\n FROM first_contributions\n GROUP BY first_pr_date\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n (SELECT SUM(new_contributors) FROM daily_new dn WHERE dn.date <= d.date) as value\nFROM daily_metrics d\nWHERE CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nGROUP BY d.date\nORDER BY d.date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Cumulative Community Contributors", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 300, + "panels": [], + "title": "Adoption", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total all-time downloads across all packages and registries. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 7 + }, + "id": 301, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "Total Downloads (All-Time)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Downloads in the last 7 days across all packages. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 7 + }, + "id": 302, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "Downloads (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total npm (TypeScript) downloads all-time. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 7 + }, + "id": 304, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'npm'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-typescript'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-typescript')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'npm'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "npm Downloads", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Daily download counts by package. PyPI retains 180 days, npm retains 365+ days. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Downloads", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 305, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n pd.downloads as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nORDER BY pd.date, pd.package", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n pd.downloads as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nORDER BY pd.date, pd.package", + "refId": "A", + "timeColumns": [ + "time" + ] + } + ], + "title": "Daily Downloads by Package", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Cumulative downloads over time showing growth trajectory. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Total Downloads", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 306, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) OVER (PARTITION BY pd.package ORDER BY pd.date) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nORDER BY pd.date, pd.package", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) OVER (PARTITION BY pd.package ORDER BY pd.date) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nORDER BY pd.date, pd.package", + "refId": "A", + "timeColumns": [ + "time" + ] + } + ], + "title": "Cumulative Downloads by Package", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Downloads per package for selected time range. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Downloads", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 308, + "options": { + "barRadius": 0.1, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY pd.package\nORDER BY downloads DESC", + "queryType": "table", + "rawQueryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY pd.package\nORDER BY downloads DESC", + "refId": "A" + } + ], + "title": "Downloads by Package", + "type": "barchart" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [ + { + "allowCustomValue": false, + "current": { + "text": [ + "sdk-typescript" + ], + "value": [ + "sdk-typescript" + ] + }, + "definition": "SELECT DISTINCT repo FROM daily_metrics", + "description": "", + "includeAll": true, + "multi": true, + "name": "repo", + "options": [], + "query": "SELECT DISTINCT repo FROM daily_metrics", + "refresh": 1, + "regex": "", + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-30d", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "TypeScript SDK", + "uid": "typescript-sdk", + "version": 10 +} \ No newline at end of file diff --git a/community-dashboard/provisioning/datasources/automatic.yaml b/community-dashboard/provisioning/datasources/automatic.yaml new file mode 100644 index 0000000..359458d --- /dev/null +++ b/community-dashboard/provisioning/datasources/automatic.yaml @@ -0,0 +1,10 @@ +apiVersion: 1 + +datasources: + - name: GitHub Metrics (SQLite) + type: frser-sqlite-datasource + access: proxy + isDefault: true + jsonData: + path: /mnt/data/metrics.db + mode: ro diff --git a/community-dashboard/src/aggregates.rs b/community-dashboard/src/aggregates.rs new file mode 100644 index 0000000..5f01afb --- /dev/null +++ b/community-dashboard/src/aggregates.rs @@ -0,0 +1,215 @@ +use anyhow::Result; +use chrono::{DateTime, Duration, NaiveDate, TimeZone, Utc}; +use rusqlite::{params, Connection}; + +pub fn compute_metrics(conn: &Connection) -> Result<()> { + // Smart detect of dirty window + let last_metric_date: Option = conn + .query_row("SELECT max(date) FROM daily_metrics", [], |row| row.get(0)) + .ok(); + + let start_date = match last_metric_date { + Some(d) => NaiveDate::parse_from_str(&d, "%Y-%m-%d") + .map(|nd| Utc.from_utc_datetime(&nd.and_hms_opt(0, 0, 0).unwrap()) - Duration::days(3)) + .unwrap_or_else(|_| Utc::now()), + None => DateTime::parse_from_rfc3339("2010-01-01T00:00:00Z") + .unwrap() + .with_timezone(&Utc), + }; + + let start_date_str = start_date.format("%Y-%m-%d").to_string(); + + // Clear out the dirty window so we can recompute + conn.execute( + "DELETE FROM daily_metrics WHERE date >= ?1", + params![start_date_str], + )?; + + // PERFORMANCE OPTIMIZATION: Calculate response times ONCE in a temp table + // Calculating this inside the daily loop was O(N^2) and incredibly slow. + conn.execute( + "CREATE TEMP TABLE IF NOT EXISTS temp_response_times AS + SELECT + parent.repo, + date(parent.created_at) as created_date, + (julianday(MIN(activity.activity_at)) - julianday(parent.created_at)) * 24 as hours_to_response + FROM ( + SELECT id, repo, number, author, created_at FROM issues + UNION ALL + SELECT id, repo, number, author, created_at FROM pull_requests + ) as parent + JOIN ( + SELECT repo, issue_number as ref_number, author, created_at as activity_at FROM issue_comments + UNION ALL + SELECT repo, pr_number as ref_number, author, submitted_at as activity_at FROM pr_reviews + UNION ALL + SELECT repo, pr_number as ref_number, author, created_at as activity_at FROM pr_review_comments + ) as activity + ON parent.repo = activity.repo + AND parent.number = activity.ref_number + AND activity.activity_at > parent.created_at + AND activity.author != parent.author + GROUP BY parent.repo, parent.number", + [], + )?; + + let now = Utc::now(); + let num_days = (now - start_date).num_days(); + + for i in 0..=num_days { + let date = start_date + Duration::days(i); + let date_str = date.format("%Y-%m-%d").to_string(); + + conn.execute( + "INSERT OR IGNORE INTO daily_metrics (date, repo) + SELECT DISTINCT ?1, repo FROM ( + SELECT repo FROM pull_requests + UNION SELECT repo FROM issues + UNION SELECT repo FROM stargazers + UNION SELECT repo FROM commits + )", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET prs_opened = (SELECT count(*) FROM pull_requests WHERE repo = daily_metrics.repo AND date(created_at) = date(daily_metrics.date)), + prs_merged = (SELECT count(*) FROM pull_requests WHERE repo = daily_metrics.repo AND merged_at IS NOT NULL AND date(merged_at) = date(daily_metrics.date)), + issues_opened = (SELECT count(*) FROM issues WHERE repo = daily_metrics.repo AND date(created_at) = date(daily_metrics.date)), + issues_closed = (SELECT count(*) FROM issues WHERE repo = daily_metrics.repo AND closed_at IS NOT NULL AND date(closed_at) = date(daily_metrics.date)) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET churn_additions = (SELECT COALESCE(SUM(additions), 0) FROM commits WHERE repo = daily_metrics.repo AND date(date) = date(daily_metrics.date)), + churn_deletions = (SELECT COALESCE(SUM(deletions), 0) FROM commits WHERE repo = daily_metrics.repo AND date(date) = date(daily_metrics.date)) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET ci_failures = (SELECT count(*) FROM workflow_runs WHERE repo = daily_metrics.repo AND conclusion = 'failure' AND date(created_at) = date(daily_metrics.date)), + ci_runs = (SELECT count(*) FROM workflow_runs WHERE repo = daily_metrics.repo AND date(created_at) = date(daily_metrics.date)) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET stars = ( + SELECT count(*) FROM stargazers + WHERE repo = daily_metrics.repo AND date(starred_at) <= date(daily_metrics.date) + ) + WHERE date = ?1", + params![date_str], + )?; + + // Open items snapshot (combined issues + PRs for backward compatibility) + conn.execute( + "UPDATE daily_metrics + SET open_items_count = ( + (SELECT count(*) FROM issues WHERE repo = daily_metrics.repo AND date(created_at) <= date(daily_metrics.date) AND (closed_at IS NULL OR date(closed_at) > date(daily_metrics.date))) + + + (SELECT count(*) FROM pull_requests WHERE repo = daily_metrics.repo AND date(created_at) <= date(daily_metrics.date) AND (closed_at IS NULL OR date(closed_at) > date(daily_metrics.date))) + ) + WHERE date = ?1", + params![date_str] + )?; + + // Open issues count (just issues, no PRs) + conn.execute( + "UPDATE daily_metrics + SET open_issues_count = ( + SELECT count(*) FROM issues WHERE repo = daily_metrics.repo AND date(created_at) <= date(daily_metrics.date) AND (closed_at IS NULL OR date(closed_at) > date(daily_metrics.date)) + ) + WHERE date = ?1", + params![date_str] + )?; + + // Open PRs count + conn.execute( + "UPDATE daily_metrics + SET open_prs_count = ( + SELECT count(*) FROM pull_requests WHERE repo = daily_metrics.repo AND date(created_at) <= date(daily_metrics.date) AND (closed_at IS NULL OR date(closed_at) > date(daily_metrics.date)) + ) + WHERE date = ?1", + params![date_str] + )?; + + // Response time stats - Optimized to use Temp Table + conn.execute( + "UPDATE daily_metrics + SET time_to_first_response = ( + SELECT AVG(hours_to_response) + FROM temp_response_times + WHERE repo = daily_metrics.repo + AND created_date = date(daily_metrics.date) + ) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET avg_issue_resolution_time = ( + SELECT AVG((julianday(closed_at) - julianday(created_at)) * 24) + FROM issues + WHERE repo = daily_metrics.repo + AND closed_at IS NOT NULL + AND date(closed_at) = date(daily_metrics.date) + ) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET avg_pr_resolution_time = ( + SELECT AVG((julianday(COALESCE(merged_at, closed_at)) - julianday(created_at)) * 24) + FROM pull_requests + WHERE repo = daily_metrics.repo + AND (merged_at IS NOT NULL OR closed_at IS NOT NULL) + AND date(COALESCE(merged_at, closed_at)) = date(daily_metrics.date) + ) + WHERE date = ?1", + params![date_str], + )?; + + // Internal vs external merge times + conn.execute( + "UPDATE daily_metrics + SET time_to_merge_internal = ( + SELECT AVG((julianday(merged_at) - julianday(created_at)) * 24) + FROM pull_requests + WHERE repo = daily_metrics.repo + AND merged_at IS NOT NULL + AND date(merged_at) = date(daily_metrics.date) + AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') + ) + WHERE date = ?1", + params![date_str], + )?; + + conn.execute( + "UPDATE daily_metrics + SET time_to_merge_external = ( + SELECT AVG((julianday(merged_at) - julianday(created_at)) * 24) + FROM pull_requests + WHERE repo = daily_metrics.repo + AND merged_at IS NOT NULL + AND date(merged_at) = date(daily_metrics.date) + AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') + ) + WHERE date = ?1", + params![date_str], + )?; + } + + // Cleanup temp table + conn.execute("DROP TABLE IF EXISTS temp_response_times", [])?; + + Ok(()) +} diff --git a/community-dashboard/src/client.rs b/community-dashboard/src/client.rs new file mode 100644 index 0000000..fe39d58 --- /dev/null +++ b/community-dashboard/src/client.rs @@ -0,0 +1,730 @@ +use anyhow::Result; +use chrono::{DateTime, Datelike, Utc}; +use http::header::ACCEPT; +use http::StatusCode; +use indicatif::ProgressBar; +use octocrab::{models, Octocrab, OctocrabBuilder}; +use rusqlite::{params, Connection}; +use serde::Deserialize; +use serde_json::Value; +use std::collections::HashSet; + +#[derive(Deserialize, Debug)] +struct SimpleUser { + login: String, +} + +#[derive(Deserialize, Debug)] +struct StarEntry { + starred_at: Option>, + user: Option, +} + +pub struct GitHubClient<'a> { + pub gh: Octocrab, + db: &'a mut Connection, + pb: ProgressBar, +} + +impl<'a> GitHubClient<'a> { + pub fn new(gh: Octocrab, db: &'a mut Connection, pb: ProgressBar) -> Self { + Self { gh, db, pb } + } + + pub async fn check_limits(&self) -> Result<()> { + let rate = self.gh.ratelimit().get().await?; + let core = rate.resources.core; + + if core.remaining < 50 { + let reset = core.reset; + let now = Utc::now().timestamp() as u64; + let wait_secs = reset.saturating_sub(now) + 10; + self.pb + .set_message(format!("Rate limit low. Sleeping {}s...", wait_secs)); + tokio::time::sleep(tokio::time::Duration::from_secs(wait_secs)).await; + } + Ok(()) + } + + pub async fn sync_org(&mut self, org: &str) -> Result<()> { + self.check_limits().await?; + let repos = self.fetch_repos(org).await?; + for repo in repos { + self.pb.set_message(format!("Syncing {}", repo.name)); + self.sync_repo(org, &repo).await?; + } + Ok(()) + } + + pub async fn sweep_org(&mut self, org: &str) -> Result<()> { + self.check_limits().await?; + let repos = self.fetch_repos(org).await?; + for repo in repos { + self.pb.set_message(format!("Sweeping {}", repo.name)); + self.sweep_repo(org, &repo).await?; + } + Ok(()) + } + + async fn fetch_repos(&self, org: &str) -> Result> { + let mut repos = Vec::new(); + let mut page = self.gh.orgs(org).list_repos().per_page(100).send().await?; + repos.extend(page.items); + while let Some(next) = page.next { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + repos.extend(page.items); + } + + repos.retain(|r| { + !r.archived.unwrap_or(false) + && !r.private.unwrap_or(false) + && !r.name.starts_with("private_") + }); + + Ok(repos) + } + + async fn sweep_repo(&self, org: &str, repo: &models::Repository) -> Result<()> { + let mut remote_open_numbers = HashSet::new(); + let route = format!("/repos/{}/{}/issues", org, repo.name); + let mut page: octocrab::Page = self + .gh + .get( + &route, + Some(&serde_json::json!({ + "state": "open", "per_page": 100 + })), + ) + .await?; + + loop { + let next_page = page.next.clone(); + for item in page.items { + if let Some(num) = item.get("number").and_then(|n| n.as_i64()) { + remote_open_numbers.insert(num); + } + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + + let mut stmt = self.db.prepare( + "SELECT number FROM issues WHERE repo = ?1 AND state = 'open' AND closed_at IS NULL AND deleted_at IS NULL" + )?; + let local_open_nums: Vec = stmt + .query_map(params![repo.name], |row| row.get(0))? + .collect::, _>>()?; + + let now = Utc::now().to_rfc3339(); + + for local_num in local_open_nums { + if !remote_open_numbers.contains(&local_num) { + self.check_limits().await?; + let issue_route = format!("/repos/{}/{}/issues/{}", org, repo.name, local_num); + + let result: Result = self.gh.get(&issue_route, None::<&()>).await; + + match result { + Ok(json) => { + let state = json + .get("state") + .and_then(|s| s.as_str()) + .unwrap_or("closed"); + let closed_at = json.get("closed_at").and_then(|s| s.as_str()); + self.db.execute( + "UPDATE issues SET state = ?1, closed_at = ?2 WHERE repo = ?3 AND number = ?4", + params![state, closed_at, repo.name, local_num] + )?; + } + Err(e) => { + if Self::is_missing_resource(&e) { + // Explicit 404/410 means deleted/missing + self.db.execute( + "UPDATE issues SET state = 'deleted', deleted_at = ?1 WHERE repo = ?2 AND number = ?3", + params![now, repo.name, local_num] + )?; + } else { + // Any other error (500, 502, timeout) is a crash. + return Err(e.into()); + } + } + } + } + } + Ok(()) + } + + async fn sync_repo(&mut self, org: &str, repo: &models::Repository) -> Result<()> { + let repo_name = &repo.name; + let last_sync_key = format!("last_sync_{}_{}", org, repo_name); + + let since: DateTime = self + .db + .query_row( + "SELECT value FROM app_state WHERE key = ?1", + params![last_sync_key], + |row| { + let s: String = row.get(0)?; + Ok(DateTime::parse_from_rfc3339(&s) + .map(|dt| dt.with_timezone(&Utc)) + .unwrap_or(Utc::now())) + }, + ) + .unwrap_or_else(|_| { + DateTime::parse_from_rfc3339("1970-01-01T00:00:00Z") + .unwrap() + .with_timezone(&Utc) + }); + + self.sync_pull_requests(org, repo_name, since).await?; + self.sync_issues(org, repo_name, since).await?; + self.sync_issue_comments(org, repo_name, since).await?; + self.sync_pr_comments(org, repo_name, since).await?; + self.sync_stars(org, repo).await?; + self.sync_commits(org, repo_name, since).await?; + self.sync_workflows(org, repo_name, since).await?; + + let now_str = Utc::now().to_rfc3339(); + self.db.execute( + "INSERT OR REPLACE INTO app_state (key, value) VALUES (?1, ?2)", + params![last_sync_key, now_str], + )?; + + Ok(()) + } + + async fn sync_commits(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + + let route = format!("/repos/{}/{}/commits", org, repo); + let mut page: octocrab::Page = self + .gh + .get( + &route, + Some(&serde_json::json!({ + "since": since.to_rfc3339(), "per_page": 100 + })), + ) + .await?; + + loop { + let next_page = page.next.clone(); + + // Optimization: Collect SHAs and check in batch locally to avoid DB thrashing + let mut shas = HashSet::new(); + for item in &page.items { + if let Some(sha) = item.get("sha").and_then(|s| s.as_str()) { + shas.insert(sha.to_string()); + } + } + + for sha in shas { + // Check if exists + let exists: bool = self + .db + .query_row("SELECT 1 FROM commits WHERE sha = ?1", params![sha], |_| { + Ok(true) + }) + .unwrap_or(false); + + if !exists { + // We must fetch details to get stats (additions/deletions) + // Check limits BEFORE the heavy call + self.check_limits().await?; + + let detail_route = format!("/repos/{}/{}/commits/{}", org, repo, sha); + let detail: Value = self.gh.get(&detail_route, None::<&()>).await?; + + let author = detail + .get("commit") + .and_then(|c| c.get("author")) + .and_then(|a| a.get("name")) + .and_then(|n| n.as_str()) + .unwrap_or("unknown"); + + let date_str = detail + .get("commit") + .and_then(|c| c.get("author")) + .and_then(|a| a.get("date")) + .and_then(|d| d.as_str()) + .unwrap_or(""); + + let stats = detail.get("stats"); + let adds = stats + .and_then(|s| s.get("additions")) + .and_then(|v| v.as_i64()) + .unwrap_or(0); + let dels = stats + .and_then(|s| s.get("deletions")) + .and_then(|v| v.as_i64()) + .unwrap_or(0); + let msg = detail + .get("commit") + .and_then(|c| c.get("message")) + .and_then(|m| m.as_str()) + .unwrap_or(""); + + self.db.execute( + "INSERT OR REPLACE INTO commits (sha, repo, author, date, additions, deletions, message) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", + params![sha, repo, author, date_str, adds, dels, msg] + )?; + } + } + + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_workflows(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + let route = format!("/repos/{}/{}/actions/runs", org, repo); + let created_filter = format!(">{}", since.format("%Y-%m-%d")); + + let mut page: octocrab::Page = self + .gh + .get( + &route, + Some(&serde_json::json!({ + "created": created_filter, "per_page": 100 + })), + ) + .await?; + + loop { + let next_page = page.next.clone(); + for run in page.items { + let id = run.get("id").and_then(|v| v.as_i64()).unwrap_or(0); + let name = run.get("name").and_then(|v| v.as_str()).unwrap_or(""); + let head = run + .get("head_branch") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let conclusion = run + .get("conclusion") + .and_then(|v| v.as_str()) + .unwrap_or("in_progress"); + let created_at = run.get("created_at").and_then(|v| v.as_str()).unwrap_or(""); + let updated_at = run.get("updated_at").and_then(|v| v.as_str()).unwrap_or(""); + + let duration = if let (Some(start), Some(end)) = ( + run.get("created_at").and_then(|v| v.as_str()), + run.get("updated_at").and_then(|v| v.as_str()), + ) { + let s = DateTime::parse_from_rfc3339(start).unwrap_or(Utc::now().into()); + let e = DateTime::parse_from_rfc3339(end).unwrap_or(Utc::now().into()); + (e - s).num_milliseconds() + } else { + 0 + }; + + self.db.execute( + "INSERT OR REPLACE INTO workflow_runs (id, repo, name, head_branch, conclusion, created_at, updated_at, duration_ms) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)", + params![id, repo, name, head, conclusion, created_at, updated_at, duration] + )?; + } + + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_stars(&mut self, org: &str, repo: &models::Repository) -> Result<()> { + self.check_limits().await?; + let token = std::env::var("GITHUB_TOKEN").unwrap_or_default(); + let star_gh = OctocrabBuilder::new() + .personal_token(token) + .add_header(ACCEPT, "application/vnd.github.star+json".to_string()) + .build()?; + + let mut remote_users = HashSet::new(); + + let route = format!("/repos/{}/{}/stargazers", org, repo.name); + let mut page: octocrab::Page = star_gh + .get(&route, Some(&serde_json::json!({ "per_page": 100 }))) + .await?; + + loop { + let next_page = page.next.clone(); + for entry in page.items { + if let (Some(starred_at), Some(user)) = (entry.starred_at, entry.user) { + remote_users.insert(user.login.clone()); + self.db.execute( + "INSERT OR REPLACE INTO stargazers (repo, user, starred_at) VALUES (?1, ?2, ?3)", + params![repo.name, user.login, starred_at.to_rfc3339()], + )?; + } + } + if let Some(next) = next_page { + self.check_limits().await?; + page = star_gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + + let mut stmt = self + .db + .prepare("SELECT user FROM stargazers WHERE repo = ?1")?; + let rows = stmt.query_map(params![repo.name], |row| row.get::<_, String>(0))?; + + let mut to_delete = Vec::new(); + for local_user in rows { + let u = local_user?; + if !remote_users.contains(&u) { + to_delete.push(u); + } + } + + for u in to_delete { + self.db.execute( + "DELETE FROM stargazers WHERE repo = ?1 AND user = ?2", + params![repo.name, u], + )?; + } + + Ok(()) + } + + async fn sync_pull_requests(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + let mut page = self + .gh + .pulls(org, repo) + .list() + .state(octocrab::params::State::All) + .sort(octocrab::params::pulls::Sort::Updated) + .direction(octocrab::params::Direction::Descending) + .per_page(100) + .send() + .await?; + + let mut keep_fetching = true; + loop { + let next_page = page.next; + for pr in page.items { + if let Some(updated) = pr.updated_at { + if updated < since { + keep_fetching = false; + break; + } + } + + let json = serde_json::to_string(&pr)?; + let pr_id = pr.id.0 as i64; + let pr_number = pr.number as i64; + let state_str = match pr.state { + Some(models::IssueState::Open) => "open", + Some(models::IssueState::Closed) => "closed", + _ => "unknown", + }; + + self.db.execute( + "INSERT OR REPLACE INTO pull_requests + (id, repo, number, state, author, title, created_at, updated_at, merged_at, closed_at, data) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)", + params![ + pr_id, repo, pr_number, state_str, + pr.user.as_ref().map(|u| u.login.clone()).unwrap_or_default(), + pr.title.unwrap_or_default(), + pr.created_at.map(|d| d.to_rfc3339()).unwrap_or_default(), + pr.updated_at.map(|d| d.to_rfc3339()).unwrap_or_default(), + pr.merged_at.map(|t| t.to_rfc3339()), + pr.closed_at.map(|t| t.to_rfc3339()), + json + ], + )?; + + if pr.updated_at.map(|t| t >= since).unwrap_or(false) { + self.sync_reviews(org, repo, pr.number).await?; + } + } + + if !keep_fetching { + break; + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_reviews(&self, org: &str, repo: &str, pr_number: u64) -> Result<()> { + let mut page = self + .gh + .pulls(org, repo) + .list_reviews(pr_number) + .per_page(100) + .send() + .await?; + loop { + let next_page = page.next; + for review in page.items { + let json = serde_json::to_string(&review)?; + let review_id = review.id.0 as i64; + let pr_num = pr_number as i64; + let state_str = review + .state + .map(|s| format!("{:?}", s).to_uppercase()) + .unwrap_or_else(|| "UNKNOWN".to_string()); + + self.db.execute( + "INSERT OR REPLACE INTO pr_reviews (id, repo, pr_number, state, author, submitted_at, data) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", + params![ + review_id, repo, pr_num, state_str, + review.user.as_ref().map(|u| u.login.clone()).unwrap_or_default(), + review.submitted_at.map(|t| t.to_rfc3339()).unwrap_or_default(), + json + ], + )?; + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_issues(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + let route = format!("/repos/{}/{}/issues", org, repo); + + // GitHub's /issues endpoint rejects very old "since" dates (returns 0 items). + // This appears to work for our use case. + let use_since_filter = since.year() >= 2010; + + let mut page: octocrab::Page = if use_since_filter { + self.gh.get(&route, Some(&serde_json::json!({ + "state": "all", "sort": "updated", "direction": "desc", "since": since.to_rfc3339(), "per_page": 100 + }))).await? + } else { + // First sync: don't pass since parameter to avoid GitHub API bug + self.gh.get(&route, Some(&serde_json::json!({ + "state": "all", "sort": "updated", "direction": "desc", "per_page": 100 + }))).await? + }; + + let mut keep_fetching = true; + loop { + let next_page = page.next.clone(); + for issue in page.items { + let updated_at_str = issue + .get("updated_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let updated_at = DateTime::parse_from_rfc3339(updated_at_str) + .map(|dt| dt.with_timezone(&Utc)) + .unwrap_or_else(|_| Utc::now()); + + if updated_at < since { + keep_fetching = false; + break; + } + if issue.get("pull_request").is_some() { + continue; + } + + let json = serde_json::to_string(&issue)?; + let id = issue.get("id").and_then(|v| v.as_i64()).unwrap_or(0); + let number = issue.get("number").and_then(|v| v.as_i64()).unwrap_or(0); + let state = issue + .get("state") + .and_then(|v| v.as_str()) + .unwrap_or("unknown"); + let author = issue + .get("user") + .and_then(|u| u.get("login")) + .and_then(|l| l.as_str()) + .unwrap_or("unknown"); + let title = issue.get("title").and_then(|v| v.as_str()).unwrap_or(""); + let created = issue + .get("created_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let closed = issue.get("closed_at").and_then(|v| v.as_str()); + + self.db.execute( + "INSERT OR REPLACE INTO issues + (id, repo, number, state, author, title, created_at, updated_at, closed_at, data) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)", + params![id, repo, number, state, author, title, created, updated_at_str, closed, json], + )?; + } + if !keep_fetching { + break; + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_issue_comments(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + let route = format!("/repos/{}/{}/issues/comments", org, repo); + let mut page: octocrab::Page = self.gh.get(&route, Some(&serde_json::json!({ + "sort": "updated", "direction": "desc", "since": since.to_rfc3339(), "per_page": 100 + }))).await?; + + let mut keep_fetching = true; + loop { + let next_page = page.next.clone(); + for comment in page.items { + let updated_at_str = comment + .get("updated_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let updated_at = DateTime::parse_from_rfc3339(updated_at_str) + .map(|dt| dt.with_timezone(&Utc)) + .unwrap_or_else(|_| Utc::now()); + + if updated_at < since { + keep_fetching = false; + break; + } + let issue_url = comment + .get("issue_url") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let issue_number: i64 = issue_url + .split('/') + .next_back() + .unwrap_or("0") + .parse() + .unwrap_or(0); + let id = comment.get("id").and_then(|v| v.as_i64()).unwrap_or(0); + let author = comment + .get("user") + .and_then(|u| u.get("login")) + .and_then(|l| l.as_str()) + .unwrap_or("unknown"); + let created = comment + .get("created_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let json = serde_json::to_string(&comment)?; + + self.db.execute( + "INSERT OR REPLACE INTO issue_comments (id, repo, issue_number, author, created_at, updated_at, data) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", + params![id, repo, issue_number, author, created, updated_at_str, json], + )?; + } + if !keep_fetching { + break; + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + async fn sync_pr_comments(&self, org: &str, repo: &str, since: DateTime) -> Result<()> { + self.check_limits().await?; + let route = format!("/repos/{}/{}/pulls/comments", org, repo); + let mut page: octocrab::Page = self.gh.get(&route, Some(&serde_json::json!({ + "sort": "updated", "direction": "desc", "since": since.to_rfc3339(), "per_page": 100 + }))).await?; + + let mut keep_fetching = true; + loop { + let next_page = page.next.clone(); + for comment in page.items { + let updated_at_str = comment + .get("updated_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let updated_at = DateTime::parse_from_rfc3339(updated_at_str) + .map(|dt| dt.with_timezone(&Utc)) + .unwrap_or_else(|_| Utc::now()); + + if updated_at < since { + keep_fetching = false; + break; + } + let pull_url = comment + .get("pull_request_url") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let pr_number: i64 = pull_url + .split('/') + .next_back() + .unwrap_or("0") + .parse() + .unwrap_or(0); + let id = comment.get("id").and_then(|v| v.as_i64()).unwrap_or(0); + let author = comment + .get("user") + .and_then(|u| u.get("login")) + .and_then(|l| l.as_str()) + .unwrap_or("unknown"); + let created = comment + .get("created_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + let json = serde_json::to_string(&comment)?; + + self.db.execute( + "INSERT OR REPLACE INTO pr_review_comments (id, repo, pr_number, author, created_at, updated_at, data) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", + params![id, repo, pr_number, author, created, updated_at_str, json], + )?; + } + if !keep_fetching { + break; + } + if let Some(next) = next_page { + self.check_limits().await?; + page = self.gh.get_page(&Some(next)).await?.unwrap(); + } else { + break; + } + } + Ok(()) + } + + fn is_missing_resource(err: &octocrab::Error) -> bool { + match err { + octocrab::Error::GitHub { source, .. } => { + source.status_code == StatusCode::NOT_FOUND + || source.status_code == StatusCode::GONE + || source.message.eq_ignore_ascii_case("Not Found") + || source.message.eq_ignore_ascii_case("Not Found.") + } + _ => false, + } + } +} diff --git a/community-dashboard/src/db.rs b/community-dashboard/src/db.rs new file mode 100644 index 0000000..c150b98 --- /dev/null +++ b/community-dashboard/src/db.rs @@ -0,0 +1,210 @@ +use anyhow::Result; +use rusqlite::Connection; +use std::path::Path; + +pub fn init_db>(path: P) -> Result { + let conn = Connection::open(path)?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS app_state ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS pull_requests ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + number INTEGER NOT NULL, + state TEXT NOT NULL, + author TEXT NOT NULL, + title TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + merged_at TEXT, + closed_at TEXT, + deleted_at TEXT, + data TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS issues ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + number INTEGER NOT NULL, + state TEXT NOT NULL, + author TEXT NOT NULL, + title TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + closed_at TEXT, + deleted_at TEXT, + data TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS issue_comments ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + issue_number INTEGER NOT NULL, + author TEXT NOT NULL, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + data TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS pr_reviews ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + pr_number INTEGER NOT NULL, + state TEXT NOT NULL, + author TEXT NOT NULL, + submitted_at TEXT NOT NULL, + data TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS pr_review_comments ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + pr_number INTEGER NOT NULL, + author TEXT NOT NULL, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + data TEXT NOT NULL + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS stargazers ( + repo TEXT NOT NULL, + user TEXT NOT NULL, + starred_at TEXT NOT NULL, + PRIMARY KEY (repo, user) + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS commits ( + sha TEXT PRIMARY KEY, + repo TEXT NOT NULL, + author TEXT NOT NULL, + date TEXT NOT NULL, + additions INTEGER DEFAULT 0, + deletions INTEGER DEFAULT 0, + message TEXT + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS workflow_runs ( + id INTEGER PRIMARY KEY, + repo TEXT NOT NULL, + name TEXT, + head_branch TEXT, + conclusion TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + duration_ms INTEGER DEFAULT 0 + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS daily_metrics ( + date TEXT NOT NULL, + repo TEXT NOT NULL, + + prs_opened INTEGER DEFAULT 0, + prs_merged INTEGER DEFAULT 0, + issues_opened INTEGER DEFAULT 0, + issues_closed INTEGER DEFAULT 0, + + churn_additions INTEGER DEFAULT 0, + churn_deletions INTEGER DEFAULT 0, + + ci_failures INTEGER DEFAULT 0, + ci_runs INTEGER DEFAULT 0, + + stars INTEGER DEFAULT 0, + + open_items_count INTEGER DEFAULT 0, + open_issues_count INTEGER DEFAULT 0, + open_prs_count INTEGER DEFAULT 0, + + time_to_first_response REAL DEFAULT 0, + avg_issue_resolution_time REAL DEFAULT 0, + avg_pr_resolution_time REAL DEFAULT 0, + + time_to_merge_internal REAL DEFAULT 0, + time_to_merge_external REAL DEFAULT 0, + + PRIMARY KEY (date, repo) + )", + [], + )?; + + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_pr_repo_updated ON pull_requests(repo, updated_at)", + [], + )?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_issues_repo_updated ON issues(repo, updated_at)", + [], + )?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_comments_repo_issue ON issue_comments(repo, issue_number)", + [], + )?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_reviews_repo_pr ON pr_reviews(repo, pr_number)", + [], + )?; + conn.execute("CREATE INDEX IF NOT EXISTS idx_review_comments_repo_pr ON pr_review_comments(repo, pr_number)", [])?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_stars_repo_date ON stargazers(repo, starred_at)", + [], + )?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_commits_repo_date ON commits(repo, date)", + [], + )?; + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_workflows_repo_date ON workflow_runs(repo, created_at)", + [], + )?; + + // Package download tracking + conn.execute( + "CREATE TABLE IF NOT EXISTS package_downloads ( + date TEXT NOT NULL, + package TEXT NOT NULL, + registry TEXT NOT NULL, + version TEXT, + downloads INTEGER DEFAULT 0, + PRIMARY KEY (date, package, registry, version) + )", + [], + )?; + + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_downloads_package_date ON package_downloads(package, date)", + [], + )?; + + Ok(conn) +} diff --git a/community-dashboard/src/downloads.rs b/community-dashboard/src/downloads.rs new file mode 100644 index 0000000..cfc4e49 --- /dev/null +++ b/community-dashboard/src/downloads.rs @@ -0,0 +1,287 @@ +use anyhow::{Context, Result}; +use chrono::{Duration, Utc}; +use rusqlite::{params, Connection}; +use serde::Deserialize; +use std::collections::HashMap; + +// ============================================================================ +// PyPI API Types +// ============================================================================ + +#[derive(Debug, Deserialize)] +struct PyPIStatsResponse { + data: Vec, +} + +#[derive(Debug, Deserialize)] +struct PyPIDataPoint { + date: String, + downloads: i64, +} + +#[derive(Debug, Deserialize)] +struct PyPIVersionResponse { + data: HashMap>, +} + +// ============================================================================ +// npm API Types +// ============================================================================ + +#[derive(Debug, Deserialize)] +struct NpmRangeResponse { + downloads: Vec, +} + +#[derive(Debug, Deserialize)] +struct NpmDownloadPoint { + day: String, + downloads: i64, +} + +#[derive(Debug, Deserialize)] +struct NpmVersionsResponse { + versions: HashMap, // version -> tarball url +} + +#[derive(Debug, Deserialize)] +struct NpmPackageInfo { + time: HashMap, // version -> publish date +} + +// ============================================================================ +// Sync Functions +// ============================================================================ + +pub async fn sync_pypi_downloads( + conn: &Connection, + package: &str, + days: i64, +) -> Result { + let client = reqwest::Client::new(); + let mut total_inserted = 0; + + // First, get overall daily downloads + let url = format!( + "https://pypistats.org/api/packages/{}/overall?mirrors=false", + package + ); + + let response: PyPIStatsResponse = client + .get(&url) + .header("User-Agent", "strands-metrics/1.0") + .send() + .await? + .json() + .await + .context(format!("Failed to fetch PyPI stats for {}", package))?; + + let cutoff = (Utc::now() - Duration::days(days)) + .format("%Y-%m-%d") + .to_string(); + + // PyPI stats are updated daily around 01:00 UTC, data is for previous day + // Skip today and yesterday to avoid incomplete data + let max_date = (Utc::now() - Duration::days(1)) + .format("%Y-%m-%d") + .to_string(); + + for point in response.data { + // Only include data within our date range, excluding incomplete recent data + if point.date >= cutoff && point.date <= max_date { + conn.execute( + "INSERT INTO package_downloads (date, package, registry, version, downloads) + VALUES (?1, ?2, 'pypi', 'total', ?3) + ON CONFLICT(date, package, registry, version) DO UPDATE SET downloads = excluded.downloads", + params![point.date, package, point.downloads], + )?; + total_inserted += 1; + } + } + + // Now get per-version downloads if available + let _version_url = format!( + "https://pypistats.org/api/packages/{}/python_minor?mirrors=false", + package + ); + + // Note: pypistats doesn't have per-package-version data easily available + // The python_minor endpoint shows by Python version, not package version + // For true per-version data, we'd need BigQuery access + // For now, we'll track totals which is most useful for adoption metrics + + Ok(total_inserted) +} + +pub async fn sync_npm_downloads( + conn: &Connection, + package: &str, + days: i64, +) -> Result { + let client = reqwest::Client::new(); + let mut total_inserted = 0; + + // npm stats are updated daily, data for a given day is available the next day + // Use yesterday as end date to avoid incomplete data + let end_date = (Utc::now() - Duration::days(1)) + .format("%Y-%m-%d") + .to_string(); + let start_date = (Utc::now() - Duration::days(days)) + .format("%Y-%m-%d") + .to_string(); + + // Get daily downloads for the date range + let url = format!( + "https://api.npmjs.org/downloads/range/{}:{}/{}", + start_date, end_date, package + ); + + let response: NpmRangeResponse = client + .get(&url) + .header("User-Agent", "strands-metrics/1.0") + .send() + .await? + .json() + .await + .context(format!("Failed to fetch npm stats for {}", package))?; + + for point in response.downloads { + conn.execute( + "INSERT INTO package_downloads (date, package, registry, version, downloads) + VALUES (?1, ?2, 'npm', 'total', ?3) + ON CONFLICT(date, package, registry, version) DO UPDATE SET downloads = excluded.downloads", + params![point.day, package, point.downloads], + )?; + total_inserted += 1; + } + + // Get per-version data from npm registry + // npm doesn't provide per-version download counts via public API + // The downloads API only gives totals + // For version breakdown, we'd need to use npm's BigQuery dataset + + Ok(total_inserted) +} + +pub async fn backfill_pypi_downloads( + conn: &Connection, + package: &str, +) -> Result { + // PyPI stats API provides ~180 days of history + sync_pypi_downloads(conn, package, 180).await +} + +pub async fn backfill_npm_downloads( + conn: &Connection, + package: &str, +) -> Result { + // npm API allows fetching up to 18 months of history + // Let's fetch 365 days to get a good history + sync_npm_downloads(conn, package, 365).await +} + +// ============================================================================ +// Config Loading +// ============================================================================ + +#[derive(Debug, Deserialize)] +pub struct PackagesConfig { + #[serde(default)] + pub repo_mappings: std::collections::HashMap>, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct PackageMapping { + pub package: String, + pub registry: String, +} + +impl PackagesConfig { + /// Get all unique packages for a given registry + pub fn packages_for_registry(&self, registry: &str) -> Vec { + let mut packages: Vec = self + .repo_mappings + .values() + .flatten() + .filter(|m| m.registry == registry) + .map(|m| m.package.clone()) + .collect(); + packages.sort(); + packages.dedup(); + packages + } +} + +pub fn load_packages_config(path: &str) -> Result { + let content = std::fs::read_to_string(path)?; + let config: PackagesConfig = serde_yaml::from_str(&content)?; + Ok(config) +} + +pub fn load_repo_mappings(conn: &Connection, config: &PackagesConfig) -> Result { + // Create table if not exists + conn.execute( + "CREATE TABLE IF NOT EXISTS repo_package_mapping ( + repo TEXT NOT NULL, + package TEXT NOT NULL, + registry TEXT NOT NULL, + PRIMARY KEY (repo, package) + )", + [], + )?; + + // Clear existing mappings + conn.execute("DELETE FROM repo_package_mapping", [])?; + + let mut count = 0; + for (repo, mappings) in &config.repo_mappings { + for mapping in mappings { + conn.execute( + "INSERT INTO repo_package_mapping (repo, package, registry) VALUES (?1, ?2, ?3)", + params![repo, mapping.package, mapping.registry], + )?; + count += 1; + } + } + + Ok(count) +} + +// ============================================================================ +// Query Helpers +// ============================================================================ + +pub fn get_total_downloads(conn: &Connection, package: &str, registry: &str) -> Result { + let total: i64 = conn.query_row( + "SELECT COALESCE(SUM(downloads), 0) FROM package_downloads + WHERE package = ?1 AND registry = ?2 AND version = 'total'", + params![package, registry], + |row| row.get(0), + )?; + Ok(total) +} + +pub fn get_downloads_by_date( + conn: &Connection, + package: &str, + registry: &str, + start_date: &str, + end_date: &str, +) -> Result> { + let mut stmt = conn.prepare( + "SELECT date, downloads FROM package_downloads + WHERE package = ?1 AND registry = ?2 AND version = 'total' + AND date >= ?3 AND date <= ?4 + ORDER BY date", + )?; + + let rows = stmt.query_map(params![package, registry, start_date, end_date], |row| { + Ok((row.get(0)?, row.get(1)?)) + })?; + + let mut results = Vec::new(); + for row in rows { + results.push(row?); + } + Ok(results) +} diff --git a/community-dashboard/src/goals.rs b/community-dashboard/src/goals.rs new file mode 100644 index 0000000..83f20de --- /dev/null +++ b/community-dashboard/src/goals.rs @@ -0,0 +1,389 @@ +use anyhow::{bail, Result}; +use rusqlite::{params, Connection}; +use serde::Deserialize; +use std::collections::HashMap; +use std::fs; +use std::path::Path; + +/// Valid directions for goal thresholds +#[derive(Debug, Deserialize, Clone, Copy, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum Direction { + /// Lower values are better (e.g., merge time, failure rate) + LowerIsBetter, + /// Higher values are better (e.g., community %, retention) + HigherIsBetter, +} + +impl Direction { + fn as_str(&self) -> &'static str { + match self { + Direction::LowerIsBetter => "lower_is_better", + Direction::HigherIsBetter => "higher_is_better", + } + } + + fn default_warning_ratio(&self) -> f64 { + match self { + Direction::LowerIsBetter => 0.75, + Direction::HigherIsBetter => 0.70, + } + } +} + +/// A goal entry from the YAML configuration +#[derive(Debug, Deserialize)] +struct GoalEntry { + value: f64, + label: Option, + direction: Direction, + warning_ratio: Option, +} + +#[derive(Debug, Deserialize)] +struct GoalsConfig { + goals: HashMap, +} + +/// A goal with all its configuration +#[derive(Debug, Clone)] +pub struct Goal { + pub metric: String, + pub value: f64, + pub label: Option, + pub direction: Direction, + pub warning_ratio: Option, +} + +impl Goal { + /// Calculate the warning threshold value + pub fn warning_value(&self) -> f64 { + let ratio = self.warning_ratio.unwrap_or_else(|| self.direction.default_warning_ratio()); + self.value * ratio + } +} + +pub fn init_goals_table(conn: &Connection) -> Result<()> { + conn.execute( + "CREATE TABLE IF NOT EXISTS goals ( + metric TEXT PRIMARY KEY, + value REAL NOT NULL, + label TEXT, + direction TEXT, + warning_ratio REAL, + updated_at TEXT NOT NULL DEFAULT (datetime('now')) + )", + [], + )?; + + // Add columns if they don't exist (migration for existing DBs) + let _ = conn.execute("ALTER TABLE goals ADD COLUMN label TEXT", []); + let _ = conn.execute("ALTER TABLE goals ADD COLUMN direction TEXT", []); + let _ = conn.execute("ALTER TABLE goals ADD COLUMN warning_ratio REAL", []); + + // Create or replace view for dynamic thresholds + // Used by Grafana's "Config from Query results" transformation + // + // Threshold logic: + // - lower_is_better: warning < goal (e.g., merge time: warn at 18h, critical at 24h) + // - higher_is_better: warning < goal (e.g., community %: warn at 14%, critical at 20%) + conn.execute("DROP VIEW IF EXISTS goal_thresholds", [])?; + conn.execute( + "CREATE VIEW IF NOT EXISTS goal_thresholds AS + SELECT + metric, + value as goal_value, + label, + direction, + warning_ratio, + CASE + WHEN direction = 'lower_is_better' THEN + value * COALESCE(warning_ratio, 0.75) + WHEN direction = 'higher_is_better' THEN + value * COALESCE(warning_ratio, 0.70) + ELSE value * 0.75 + END as warning_value + FROM goals + WHERE direction IS NOT NULL", + [], + )?; + + // Create team_members table for configurable team lists + conn.execute( + "CREATE TABLE IF NOT EXISTS team_members ( + username TEXT PRIMARY KEY, + display_name TEXT, + added_at TEXT NOT NULL DEFAULT (datetime('now')) + )", + [], + )?; + + Ok(()) +} + +pub fn load_goals>(conn: &Connection, yaml_path: P) -> Result { + let path = yaml_path.as_ref(); + let content = fs::read_to_string(path)?; + let config: GoalsConfig = serde_yaml::from_str(&content)?; + + let mut count = 0; + for (metric, entry) in config.goals { + // Validate warning_ratio is in valid range + if let Some(ratio) = entry.warning_ratio { + if ratio <= 0.0 || ratio >= 1.0 { + bail!( + "warning_ratio must be between 0 and 1 (exclusive), got {} for metric '{}'", + ratio, + metric + ); + } + } + + let direction_str = entry.direction.as_str(); + + conn.execute( + "INSERT INTO goals (metric, value, label, direction, warning_ratio, updated_at) + VALUES (?1, ?2, ?3, ?4, ?5, datetime('now')) + ON CONFLICT(metric) DO UPDATE SET + value = excluded.value, + label = excluded.label, + direction = excluded.direction, + warning_ratio = excluded.warning_ratio, + updated_at = datetime('now')", + params![metric, entry.value, entry.label, direction_str, entry.warning_ratio], + )?; + count += 1; + } + + Ok(count) +} + +pub fn list_goals(conn: &Connection) -> Result> { + let mut stmt = conn.prepare( + "SELECT metric, value, label, direction, warning_ratio FROM goals ORDER BY metric", + )?; + + let rows = stmt.query_map([], |row| { + let direction_str: Option = row.get(3)?; + let direction = match direction_str.as_deref() { + Some("lower_is_better") => Direction::LowerIsBetter, + Some("higher_is_better") => Direction::HigherIsBetter, + _ => Direction::LowerIsBetter, // Default fallback + }; + + Ok(Goal { + metric: row.get(0)?, + value: row.get(1)?, + label: row.get(2)?, + direction, + warning_ratio: row.get(4)?, + }) + })?; + + let mut goals = Vec::new(); + for row in rows { + goals.push(row?); + } + Ok(goals) +} + +/// A team member entry from YAML configuration +#[derive(Debug, Deserialize)] +pub struct TeamMemberEntry { + pub username: String, + pub display_name: Option, +} + +#[derive(Debug, Deserialize)] +struct TeamConfig { + members: Vec, +} + +/// Load team members from a YAML config file +pub fn load_team_from_yaml>(conn: &Connection, yaml_path: P) -> Result { + let content = fs::read_to_string(yaml_path)?; + let config: TeamConfig = serde_yaml::from_str(&content)?; + + let mut count = 0; + for member in config.members { + conn.execute( + "INSERT INTO team_members (username, display_name, added_at) + VALUES (?1, ?2, datetime('now')) + ON CONFLICT(username) DO UPDATE SET + display_name = excluded.display_name, + added_at = datetime('now')", + params![member.username, member.display_name], + )?; + count += 1; + } + Ok(count) +} + +/// Load team members from a list (for CLI --members flag) +pub fn load_team_members(conn: &Connection, members: &[(&str, Option<&str>)]) -> Result { + let mut count = 0; + for (username, display_name) in members { + conn.execute( + "INSERT INTO team_members (username, display_name, added_at) + VALUES (?1, ?2, datetime('now')) + ON CONFLICT(username) DO UPDATE SET + display_name = excluded.display_name, + added_at = datetime('now')", + params![username, display_name], + )?; + count += 1; + } + Ok(count) +} + +#[cfg(test)] +mod tests { + use super::*; + use rusqlite::Connection; + + fn setup_test_db() -> Connection { + let conn = Connection::open_in_memory().unwrap(); + init_goals_table(&conn).unwrap(); + conn + } + + #[test] + fn test_init_creates_tables_and_view() { + let conn = setup_test_db(); + + // Check goals table exists + let table_exists: i32 = conn + .query_row( + "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='goals'", + [], + |row| row.get(0), + ) + .unwrap(); + assert_eq!(table_exists, 1); + + // Check view exists + let view_exists: i32 = conn + .query_row( + "SELECT COUNT(*) FROM sqlite_master WHERE type='view' AND name='goal_thresholds'", + [], + |row| row.get(0), + ) + .unwrap(); + assert_eq!(view_exists, 1); + + // Check team_members table exists + let team_table_exists: i32 = conn + .query_row( + "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='team_members'", + [], + |row| row.get(0), + ) + .unwrap(); + assert_eq!(team_table_exists, 1); + } + + #[test] + fn test_warning_value_lower_is_better_default() { + let conn = setup_test_db(); + conn.execute( + "INSERT INTO goals (metric, value, direction) VALUES ('test_metric', 100.0, 'lower_is_better')", + [], + ) + .unwrap(); + + let warning: f64 = conn + .query_row( + "SELECT warning_value FROM goal_thresholds WHERE metric = 'test_metric'", + [], + |row| row.get(0), + ) + .unwrap(); + + assert_eq!(warning, 75.0); // 100 * 0.75 default + } + + #[test] + fn test_warning_value_higher_is_better_default() { + let conn = setup_test_db(); + conn.execute( + "INSERT INTO goals (metric, value, direction) VALUES ('test_metric', 100.0, 'higher_is_better')", + [], + ) + .unwrap(); + + let warning: f64 = conn + .query_row( + "SELECT warning_value FROM goal_thresholds WHERE metric = 'test_metric'", + [], + |row| row.get(0), + ) + .unwrap(); + + assert_eq!(warning, 70.0); // 100 * 0.70 default + } + + #[test] + fn test_warning_value_custom_ratio() { + let conn = setup_test_db(); + conn.execute( + "INSERT INTO goals (metric, value, direction, warning_ratio) VALUES ('test_metric', 100.0, 'lower_is_better', 0.5)", + [], + ) + .unwrap(); + + let warning: f64 = conn + .query_row( + "SELECT warning_value FROM goal_thresholds WHERE metric = 'test_metric'", + [], + |row| row.get(0), + ) + .unwrap(); + + assert_eq!(warning, 50.0); // 100 * 0.5 custom + } + + #[test] + fn test_list_goals_returns_struct() { + let conn = setup_test_db(); + conn.execute( + "INSERT INTO goals (metric, value, label, direction, warning_ratio) + VALUES ('merge_time', 24.0, 'Goal (24h)', 'lower_is_better', 0.75)", + [], + ) + .unwrap(); + + let goals = list_goals(&conn).unwrap(); + assert_eq!(goals.len(), 1); + + let goal = &goals[0]; + assert_eq!(goal.metric, "merge_time"); + assert_eq!(goal.value, 24.0); + assert_eq!(goal.label, Some("Goal (24h)".to_string())); + assert_eq!(goal.direction, Direction::LowerIsBetter); + assert_eq!(goal.warning_ratio, Some(0.75)); + assert_eq!(goal.warning_value(), 18.0); // 24 * 0.75 + } + + #[test] + fn test_direction_default_ratios() { + assert_eq!(Direction::LowerIsBetter.default_warning_ratio(), 0.75); + assert_eq!(Direction::HigherIsBetter.default_warning_ratio(), 0.70); + } + + #[test] + fn test_team_members_table() { + let conn = setup_test_db(); + + let members = vec![ + ("alice", Some("Alice Smith")), + ("bob", None), + ]; + let count = load_team_members(&conn, &members).unwrap(); + assert_eq!(count, 2); + + let stored_count: i32 = conn + .query_row("SELECT COUNT(*) FROM team_members", [], |row| row.get(0)) + .unwrap(); + assert_eq!(stored_count, 2); + } +} diff --git a/community-dashboard/src/main.rs b/community-dashboard/src/main.rs new file mode 100644 index 0000000..e1daf83 --- /dev/null +++ b/community-dashboard/src/main.rs @@ -0,0 +1,242 @@ +mod aggregates; +mod client; +mod db; +mod downloads; +mod goals; + +use anyhow::Result; +use clap::{Parser, Subcommand}; +use client::GitHubClient; +use db::init_db; +use goals::Direction; +use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use octocrab::OctocrabBuilder; +use std::path::PathBuf; +use std::sync::Arc; +use tracing::level_filters::LevelFilter; + +const ORG: &str = "strands-agents"; + +#[derive(Parser)] +#[clap(author, version, about)] +struct Cli { + #[clap(long, short, default_value = "metrics.db")] + db_path: PathBuf, + #[clap(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Smart sync. Grabs only what is new. + Sync, + /// Garbage collection. Checks open items against reality and marks missing ones as deleted. + Sweep, + /// Run raw SQL. + Query { sql: String }, + /// Load goals from YAML config file into the database. + LoadGoals { + /// Path to goals.yaml file + #[clap(default_value = "goals.yaml")] + config_path: PathBuf, + }, + /// List all configured goals. + ListGoals, + /// Load team members into the database for dashboard queries. + LoadTeam { + /// Path to team.yaml config file + #[clap(default_value = "team.yaml")] + config_path: PathBuf, + /// Comma-separated list of GitHub usernames (overrides config file) + #[clap(long, value_delimiter = ',')] + members: Option>, + }, + /// Sync package download stats from PyPI and npm. + SyncDownloads { + /// Path to packages.yaml config file + #[clap(long, default_value = "packages.yaml")] + config_path: PathBuf, + /// Number of days to fetch (default: 30) + #[clap(long, default_value = "30")] + days: i64, + }, + /// Backfill historical download data (PyPI: ~180 days, npm: ~365 days). + BackfillDownloads { + /// Path to packages.yaml config file + #[clap(long, default_value = "packages.yaml")] + config_path: PathBuf, + }, +} + +/// Create a spinner progress bar with consistent styling +fn create_spinner(m: &Arc, message: &str) -> ProgressBar { + let sty = ProgressStyle::with_template("{spinner:.green} {msg}") + .unwrap() + .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ "); + let pb = m.add(ProgressBar::new_spinner()); + pb.set_style(sty); + pb.enable_steady_tick(std::time::Duration::from_millis(120)); + pb.set_message(message.to_string()); + pb +} + +#[tokio::main] +async fn main() -> Result<()> { + tracing_subscriber::fmt() + .with_writer(std::io::stderr) + .with_max_level(LevelFilter::WARN) + .init(); + + let args = Cli::parse(); + let mut conn = init_db(&args.db_path)?; + goals::init_goals_table(&conn)?; + + match args.command { + Commands::Sync => { + let gh_token = std::env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN must be set"); + let octocrab = OctocrabBuilder::new().personal_token(gh_token).build()?; + + let m = Arc::new(MultiProgress::new()); + let pb = create_spinner(&m, "Initializing Sync..."); + + let mut client = GitHubClient::new(octocrab, &mut conn, pb.clone()); + + client.sync_org(ORG).await?; + + pb.set_message("Calculating metrics..."); + aggregates::compute_metrics(&conn)?; + + pb.finish_with_message("Done!"); + } + Commands::Sweep => { + let gh_token = std::env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN must be set"); + let octocrab = OctocrabBuilder::new().personal_token(gh_token).build()?; + + let m = Arc::new(MultiProgress::new()); + let pb = create_spinner(&m, "Starting Sweep..."); + + let mut client = GitHubClient::new(octocrab, &mut conn, pb.clone()); + client.sweep_org(ORG).await?; + + pb.finish_with_message("Sweep complete."); + } + Commands::Query { sql } => { + let mut stmt = conn.prepare(&sql)?; + let column_count = stmt.column_count(); + let names: Vec = stmt.column_names().into_iter().map(String::from).collect(); + + println!("{}", names.join(" | ")); + println!("{}", "-".repeat(names.len() * 15)); + + let mut rows = stmt.query([])?; + while let Some(row) = rows.next()? { + let mut row_values = Vec::new(); + for i in 0..column_count { + let val = row.get_ref(i)?; + let text = match val { + rusqlite::types::ValueRef::Null => "NULL".to_string(), + rusqlite::types::ValueRef::Integer(i) => i.to_string(), + rusqlite::types::ValueRef::Real(f) => f.to_string(), + rusqlite::types::ValueRef::Text(t) => { + String::from_utf8_lossy(t).to_string() + } + rusqlite::types::ValueRef::Blob(_) => "".to_string(), + }; + row_values.push(text); + } + println!("{}", row_values.join(" | ")); + } + } + Commands::LoadGoals { config_path } => { + let count = goals::load_goals(&conn, &config_path)?; + println!("Loaded {} goals from {:?}", count, config_path); + } + Commands::ListGoals => { + let all_goals = goals::list_goals(&conn)?; + println!( + "{:<40} | {:>10} | {:<20} | {:<15} | {}", + "Metric", "Value", "Label", "Direction", "Warning Ratio" + ); + println!("{}", "-".repeat(110)); + for goal in all_goals { + let label_str = goal.label.as_deref().unwrap_or("-"); + let dir_str = match goal.direction { + Direction::LowerIsBetter => "lower_is_better", + Direction::HigherIsBetter => "higher_is_better", + }; + let ratio_str = goal + .warning_ratio + .map(|r| format!("{:.2}", r)) + .unwrap_or_else(|| "-".to_string()); + println!( + "{:<40} | {:>10} | {:<20} | {:<15} | {}", + goal.metric, goal.value, label_str, dir_str, ratio_str + ); + } + } + Commands::LoadTeam { config_path, members } => { + let count = if let Some(member_list) = members { + // Use --members flag if provided + let member_tuples: Vec<(&str, Option<&str>)> = + member_list.iter().map(|m| (m.as_str(), None)).collect(); + goals::load_team_members(&conn, &member_tuples)? + } else { + // Load from config file + goals::load_team_from_yaml(&conn, &config_path)? + }; + println!("Loaded {} team members", count); + } + Commands::SyncDownloads { config_path, days } => { + let config = downloads::load_packages_config(config_path.to_str().unwrap())?; + + // Load repo-to-package mappings + let mapping_count = downloads::load_repo_mappings(&conn, &config)?; + println!("Loaded {} repo-to-package mappings\n", mapping_count); + + println!("Syncing PyPI packages..."); + for package in config.packages_for_registry("pypi") { + match downloads::sync_pypi_downloads(&conn, &package, days).await { + Ok(count) => println!(" {} - {} data points", package, count), + Err(e) => eprintln!(" {} - Error: {}", package, e), + } + } + + println!("\nSyncing npm packages..."); + for package in config.packages_for_registry("npm") { + match downloads::sync_npm_downloads(&conn, &package, days).await { + Ok(count) => println!(" {} - {} data points", package, count), + Err(e) => eprintln!(" {} - Error: {}", package, e), + } + } + + println!("\nDownload sync complete!"); + } + Commands::BackfillDownloads { config_path } => { + let config = downloads::load_packages_config(config_path.to_str().unwrap())?; + + // Load repo-to-package mappings + let mapping_count = downloads::load_repo_mappings(&conn, &config)?; + println!("Loaded {} repo-to-package mappings\n", mapping_count); + + println!("Backfilling PyPI packages (up to 180 days)..."); + for package in config.packages_for_registry("pypi") { + match downloads::backfill_pypi_downloads(&conn, &package).await { + Ok(count) => println!(" {} - {} data points", package, count), + Err(e) => eprintln!(" {} - Error: {}", package, e), + } + } + + println!("\nBackfilling npm packages (up to 365 days)..."); + for package in config.packages_for_registry("npm") { + match downloads::backfill_npm_downloads(&conn, &package).await { + Ok(count) => println!(" {} - {} data points", package, count), + Err(e) => eprintln!(" {} - Error: {}", package, e), + } + } + + println!("\nBackfill complete!"); + } + } + + Ok(()) +} diff --git a/community-dashboard/team.yaml b/community-dashboard/team.yaml new file mode 100644 index 0000000..031510f --- /dev/null +++ b/community-dashboard/team.yaml @@ -0,0 +1,20 @@ +# Strands Team Configuration +# Team members listed here are used by the Team Dashboard for performance tracking. +# Edit this file and run `strands-metrics load-team` to update. +# +# NOTE: This is different from GitHub org membership (author_association). +# - team.yaml: Specific people you want to track in Team Dashboard +# - author_association: All GitHub org members/collaborators (used by other dashboards) + +members: + - username: afarntrog + - username: lizradway + - username: JackYPCOnline + - username: chaynabors + - username: dbschmigelski + - username: zastrowm + - username: mehtarac + - username: mkmeral + - username: Unshure + - username: pgrayy + - username: poshinchen From 19e1ab199a57d8dc60e95e9900f65850c52932ac Mon Sep 17 00:00:00 2001 From: Jonathan Segev Date: Sat, 14 Feb 2026 20:17:09 -0500 Subject: [PATCH 06/22] feat: Add community dashboard with metrics CLI, Grafana dashboards, and AWS deployment Add a comprehensive GitHub metrics dashboard for the strands-agents org: - Rust CLI (strands-metrics) that syncs GitHub data (PRs, issues, stars, commits, CI runs, reviews, comments) and PyPI/npm download stats into SQLite - 7 Grafana dashboards organized in 3 folders (General, SDKs, Operations): Executive Summary, Health, Python SDK, TypeScript SDK, Evaluations, Team Performance, and Triage - Configurable goal thresholds (goals.yaml) with warning levels - Team member tracking (team.yaml) for the Team Performance dashboard - Package download tracking (packages.yaml) from PyPI and npm registries - Docker setup with supercronic for daily automated sync - AWS CDK stack (Fargate + EFS + ALB + CloudFront) for production deployment - GitHub Actions workflow for daily metrics.db updates Builds on the Docker/CDK infrastructure from #30 by @mkmeral, adding dashboard organization, download tracking, goal configuration, and team management. Verified: cargo check, cargo clippy (zero warnings), cargo test (7/7 pass). --- .github/workflows/community-dashboard.yaml | 10 +- community-dashboard/.gitignore | 3 +- community-dashboard/README.md | 58 +- community-dashboard/docker-compose.yaml | 21 - community-dashboard/docker/Dockerfile | 9 +- community-dashboard/docker/entrypoint.sh | 3 +- community-dashboard/docker/sync-all.sh | 24 + .../provisioning/datasources/automatic.yaml | 2 +- .../strands-metrics/Cargo.lock | 3129 +++++++++++++++++ .../{ => strands-metrics}/Cargo.toml | 0 .../{ => strands-metrics}/src/aggregates.rs | 0 .../{ => strands-metrics}/src/client.rs | 0 .../{ => strands-metrics}/src/db.rs | 0 .../{ => strands-metrics}/src/downloads.rs | 54 - .../{ => strands-metrics}/src/goals.rs | 2 + .../{ => strands-metrics}/src/main.rs | 14 +- 16 files changed, 3198 insertions(+), 131 deletions(-) delete mode 100644 community-dashboard/docker-compose.yaml create mode 100644 community-dashboard/docker/sync-all.sh create mode 100644 community-dashboard/strands-metrics/Cargo.lock rename community-dashboard/{ => strands-metrics}/Cargo.toml (100%) rename community-dashboard/{ => strands-metrics}/src/aggregates.rs (100%) rename community-dashboard/{ => strands-metrics}/src/client.rs (100%) rename community-dashboard/{ => strands-metrics}/src/db.rs (100%) rename community-dashboard/{ => strands-metrics}/src/downloads.rs (82%) rename community-dashboard/{ => strands-metrics}/src/goals.rs (99%) rename community-dashboard/{ => strands-metrics}/src/main.rs (95%) diff --git a/.github/workflows/community-dashboard.yaml b/.github/workflows/community-dashboard.yaml index cd0b292..8e6b19b 100644 --- a/.github/workflows/community-dashboard.yaml +++ b/.github/workflows/community-dashboard.yaml @@ -10,7 +10,7 @@ permissions: defaults: run: - working-directory: community-dashboard + working-directory: community-dashboard/strands-metrics jobs: update-metrics: @@ -29,8 +29,8 @@ jobs: path: | ~/.cargo/registry ~/.cargo/git - community-dashboard/target - key: ${{ runner.os }}-cargo-${{ hashFiles('community-dashboard/Cargo.toml') }} + community-dashboard/strands-metrics/target + key: ${{ runner.os }}-cargo-${{ hashFiles('community-dashboard/strands-metrics/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo- @@ -52,10 +52,10 @@ jobs: run: cargo run --release -- sync-downloads - name: Load Goals Configuration - run: cargo run --release -- load-goals goals.yaml + run: cargo run --release -- load-goals - name: Load Team Configuration - run: cargo run --release -- load-team team.yaml + run: cargo run --release -- load-team - name: Commit and Push to Main working-directory: . diff --git a/community-dashboard/.gitignore b/community-dashboard/.gitignore index e963587..441f0a9 100644 --- a/community-dashboard/.gitignore +++ b/community-dashboard/.gitignore @@ -1,6 +1,5 @@ metrics.db -target/ -Cargo.lock +strands-metrics/target/ # CDK cdk/node_modules/ diff --git a/community-dashboard/README.md b/community-dashboard/README.md index 1520a62..7574313 100644 --- a/community-dashboard/README.md +++ b/community-dashboard/README.md @@ -8,22 +8,24 @@ Deployable locally via Docker Compose or to AWS via CDK (Fargate + EFS + CloudFr ``` community-dashboard/ -├── Cargo.toml # Rust CLI project -├── src/ # strands-metrics CLI source -│ ├── main.rs # CLI entry point (sync, sweep, query, etc.) -│ ├── client.rs # GitHub API client (octocrab) -│ ├── db.rs # SQLite schema & initialization -│ ├── downloads.rs # PyPI/npm download tracking -│ ├── goals.rs # Goal thresholds & team management -│ └── aggregates.rs # Daily metric computation +├── strands-metrics/ # Rust CLI project +│ ├── Cargo.toml +│ ├── Cargo.lock +│ └── src/ +│ ├── main.rs # CLI entry point (sync, sweep, query, etc.) +│ ├── client.rs # GitHub API client (octocrab) +│ ├── db.rs # SQLite schema & initialization +│ ├── downloads.rs # PyPI/npm download tracking +│ ├── goals.rs # Goal thresholds & team management +│ └── aggregates.rs # Daily metric computation ├── goals.yaml # Configurable goal thresholds ├── team.yaml # Team members for performance tracking ├── packages.yaml # Package-to-registry mappings -├── docker-compose.yaml # Quick local Grafana (read-only) ├── docker/ │ ├── Dockerfile # Unified Grafana + metrics-sync image │ ├── docker-compose.local.yaml # Local dev with auto-sync -│ └── entrypoint.sh # Container startup script +│ ├── entrypoint.sh # Container startup script +│ └── sync-all.sh # Full sync pipeline (used by cron) ├── provisioning/ │ ├── datasources/ │ │ └── automatic.yaml # SQLite datasource config @@ -46,19 +48,9 @@ community-dashboard/ └── cdk.json ``` -## Quick Start (Local) +## Quick Start -### Option A: Docker Compose with existing database - -If you already have a `metrics.db`, place it in this directory and run: - -```bash -docker compose up -``` - -Open [http://localhost:3000](http://localhost:3000). Grafana starts in anonymous viewer mode with all dashboards pre-loaded. - -### Option B: Docker with auto-sync +### Local dev with auto-sync Build the unified image that syncs GitHub data automatically: @@ -66,13 +58,15 @@ Build the unified image that syncs GitHub data automatically: GITHUB_TOKEN=ghp_xxx docker compose -f docker/docker-compose.local.yaml up --build ``` -This builds the Rust CLI, runs an initial sync on startup, and schedules daily updates at 06:00 UTC via supercronic. +Open [http://localhost:3000](http://localhost:3000). This builds the Rust CLI, runs an initial sync on startup, and schedules daily updates at 06:00 UTC via supercronic. -### Option C: Standalone CLI +### Standalone CLI Build and run `strands-metrics` directly: ```bash +cd strands-metrics + # Build cargo build --release @@ -86,10 +80,10 @@ GITHUB_TOKEN=ghp_xxx cargo run --release -- sweep cargo run --release -- sync-downloads # Load goal thresholds into the database -cargo run --release -- load-goals goals.yaml +cargo run --release -- load-goals # Load team members for the Team dashboard -cargo run --release -- load-team team.yaml +cargo run --release -- load-team # Backfill historical downloads (PyPI: ~180 days, npm: ~365 days) cargo run --release -- backfill-downloads @@ -98,12 +92,6 @@ cargo run --release -- backfill-downloads cargo run --release -- query "SELECT repo, SUM(prs_merged) FROM daily_metrics GROUP BY repo" ``` -Then start Grafana to visualize: - -```bash -docker compose up -``` - ## CLI Commands | Command | Description | @@ -111,9 +99,9 @@ docker compose up | `sync` | Incremental sync of GitHub data (PRs, issues, stars, commits, CI, reviews, comments) | | `sweep` | Garbage collection -- checks open items against GitHub and marks missing ones as deleted | | `query ` | Run raw SQL against the metrics database | -| `load-goals [path]` | Load goal thresholds from YAML into the database | +| `load-goals [path]` | Load goal thresholds from YAML into the database (default: `../goals.yaml`) | | `list-goals` | Display all configured goal thresholds | -| `load-team [path]` | Load team members from YAML (or `--members alice,bob`) | +| `load-team [path]` | Load team members from YAML or `--members alice,bob` (default: `../team.yaml`) | | `sync-downloads` | Sync recent package downloads from PyPI and npm (default: 30 days) | | `backfill-downloads` | Backfill historical download data (PyPI: ~180 days, npm: ~365 days) | @@ -121,7 +109,7 @@ docker compose up | Flag | Default | Description | |------|---------|-------------| -| `--db-path` / `-d` | `metrics.db` | Path to the SQLite database file | +| `--db-path` / `-d` | `../metrics.db` | Path to the SQLite database file | ## Dashboards diff --git a/community-dashboard/docker-compose.yaml b/community-dashboard/docker-compose.yaml deleted file mode 100644 index 56ed819..0000000 --- a/community-dashboard/docker-compose.yaml +++ /dev/null @@ -1,21 +0,0 @@ -services: - grafana: - image: grafana/grafana:latest - container_name: grafana-sqlite-viz - user: "0:0" - ports: - - "3000:3000" - volumes: - - .:/mnt/data:ro - - ./provisioning/datasources:/etc/grafana/provisioning/datasources - - ./provisioning/dashboards:/etc/grafana/provisioning/dashboards - environment: - - GF_INSTALL_PLUGINS=frser-sqlite-datasource - - GF_PLUGIN_FRSER_SQLITE_DATASOURCE_ALLOW_LOCAL_MODE=true - - GF_AUTH_ANONYMOUS_ENABLED=true - - GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer - - GF_AUTH_BASIC_ENABLED=false - - GF_AUTH_DISABLE_LOGIN_FORM=true - - GF_USERS_ALLOW_SIGN_UP=false - - GF_SECURITY_ALLOW_EMBEDDING=true - restart: always diff --git a/community-dashboard/docker/Dockerfile b/community-dashboard/docker/Dockerfile index ffbf442..776065b 100644 --- a/community-dashboard/docker/Dockerfile +++ b/community-dashboard/docker/Dockerfile @@ -8,8 +8,8 @@ RUN apk add --no-cache musl-dev pkgconfig openssl-dev openssl-libs-static WORKDIR /build # Copy the Rust project source -COPY Cargo.toml Cargo.lock* ./ -COPY src/ ./src/ +COPY strands-metrics/Cargo.toml strands-metrics/Cargo.lock* ./ +COPY strands-metrics/src/ ./src/ # Build in release mode (statically linked against musl) RUN cargo build --release @@ -42,9 +42,10 @@ COPY goals.yaml /etc/strands/goals.yaml COPY team.yaml /etc/strands/team.yaml COPY packages.yaml /etc/strands/packages.yaml -# Copy entrypoint script +# Copy entrypoint and sync scripts COPY docker/entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh +COPY docker/sync-all.sh /usr/local/bin/sync-all.sh +RUN chmod +x /entrypoint.sh /usr/local/bin/sync-all.sh # Create the data directory for EFS / local mount RUN mkdir -p /var/lib/grafana/data diff --git a/community-dashboard/docker/entrypoint.sh b/community-dashboard/docker/entrypoint.sh index 2dc35c3..ecfffcb 100644 --- a/community-dashboard/docker/entrypoint.sh +++ b/community-dashboard/docker/entrypoint.sh @@ -35,7 +35,6 @@ else fi # ── Load configuration ───────────────────────────────────────────────────── -# Load goals and team config into the database on every startup echo "[entrypoint] Loading goals configuration..." strands-metrics --db-path "$DB_PATH" load-goals "$CONFIG_DIR/goals.yaml" || \ echo "[entrypoint] WARNING: Failed to load goals." @@ -54,7 +53,7 @@ strands-metrics --db-path "$DB_PATH" sync-downloads --config-path "$CONFIG_DIR/p # via /proc/1/fd/1 so it shows up in docker logs / CloudWatch. CRONTAB="/tmp/crontab" cat > "$CRONTAB" <<'CRONEOF' -0 6 * * * strands-metrics --db-path /var/lib/grafana/data/metrics.db sync >> /proc/1/fd/1 2>&1 && strands-metrics --db-path /var/lib/grafana/data/metrics.db sweep >> /proc/1/fd/1 2>&1 && strands-metrics --db-path /var/lib/grafana/data/metrics.db sync-downloads --config-path /etc/strands/packages.yaml >> /proc/1/fd/1 2>&1 && strands-metrics --db-path /var/lib/grafana/data/metrics.db load-goals /etc/strands/goals.yaml >> /proc/1/fd/1 2>&1 && strands-metrics --db-path /var/lib/grafana/data/metrics.db load-team /etc/strands/team.yaml >> /proc/1/fd/1 2>&1 +0 6 * * * sync-all.sh >> /proc/1/fd/1 2>&1 CRONEOF echo "[entrypoint] Starting supercronic (daily sync at 06:00 UTC)..." diff --git a/community-dashboard/docker/sync-all.sh b/community-dashboard/docker/sync-all.sh new file mode 100644 index 0000000..a000e26 --- /dev/null +++ b/community-dashboard/docker/sync-all.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# Full metrics sync pipeline. +# Called by supercronic daily and can be run manually. +set -e + +DB_PATH="/var/lib/grafana/data/metrics.db" +CONFIG_DIR="/etc/strands" + +echo "[sync-all] Starting GitHub data sync..." +strands-metrics --db-path "$DB_PATH" sync + +echo "[sync-all] Running garbage collection..." +strands-metrics --db-path "$DB_PATH" sweep + +echo "[sync-all] Syncing package downloads..." +strands-metrics --db-path "$DB_PATH" sync-downloads --config-path "$CONFIG_DIR/packages.yaml" + +echo "[sync-all] Loading goals configuration..." +strands-metrics --db-path "$DB_PATH" load-goals "$CONFIG_DIR/goals.yaml" + +echo "[sync-all] Loading team configuration..." +strands-metrics --db-path "$DB_PATH" load-team "$CONFIG_DIR/team.yaml" + +echo "[sync-all] Sync complete." diff --git a/community-dashboard/provisioning/datasources/automatic.yaml b/community-dashboard/provisioning/datasources/automatic.yaml index 359458d..c3c6be5 100644 --- a/community-dashboard/provisioning/datasources/automatic.yaml +++ b/community-dashboard/provisioning/datasources/automatic.yaml @@ -6,5 +6,5 @@ datasources: access: proxy isDefault: true jsonData: - path: /mnt/data/metrics.db + path: /var/lib/grafana/data/metrics.db mode: ro diff --git a/community-dashboard/strands-metrics/Cargo.lock b/community-dashboard/strands-metrics/Cargo.lock new file mode 100644 index 0000000..c0d1f33 --- /dev/null +++ b/community-dashboard/strands-metrics/Cargo.lock @@ -0,0 +1,3129 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + +[[package]] +name = "arc-swap" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" +dependencies = [ + "rustversion", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87a0c0e6148f11f01f32650a2ea02d532b2ad4e81d8bd41e6e565b5adc5e6082" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "cargo_metadata" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clap" +version = "4.5.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "console" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.61.2", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash 0.2.0", +] + +[[package]] +name = "hashlink" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "log", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "indicatif" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" +dependencies = [ + "console", + "portable-atomic", + "unicode-width", + "unit-prefix", + "web-time", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "10.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1" +dependencies = [ + "base64", + "ed25519-dalek", + "getrandom 0.2.17", + "hmac", + "js-sys", + "p256", + "p384", + "pem", + "rand", + "rsa", + "serde", + "serde_json", + "sha2", + "signature", + "simple_asn1", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libsqlite3-sys" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b4103cffefa72eb8428cb6b47d6627161e51c2739fc5e3b734584157bc642a" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "native-tls" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5d26952a508f321b4d3d2e80e78fc2603eaefcdf0c30783867f19586518bdc" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "octocrab" +version = "0.49.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f6f72d7084a80bf261bb6b6f83bd633323d5633d5ec7988c6c95b20448b2b5" +dependencies = [ + "arc-swap", + "async-trait", + "base64", + "bytes", + "cargo_metadata", + "cfg-if", + "chrono", + "either", + "futures", + "futures-util", + "getrandom 0.2.17", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-timeout", + "hyper-util", + "jsonwebtoken", + "once_cell", + "percent-encoding", + "pin-project", + "secrecy", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "snafu", + "tokio", + "tower", + "tower-http", + "tracing", + "url", + "web-time", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rsqlite-vfs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a1f2315036ef6b1fbacd1972e8ee7688030b0a2121edfc2a6550febd41574d" +dependencies = [ + "hashbrown 0.16.1", + "thiserror", +] + +[[package]] +name = "rusqlite" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c93dd1c9683b438c392c492109cb702b8090b2bfc8fed6f6e4eb4523f17af3" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", + "sqlite-wasm-rs", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" +dependencies = [ + "bitflags", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321c8673b092a9a42605034a9879d73cb79101ed5fd117bc9a597b89b4e9e61a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "snafu" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "socket2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlite-wasm-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4206ed3a67690b9c29b77d728f6acc3ce78f16bf846d83c94f76400320181b" +dependencies = [ + "cc", + "js-sys", + "rsqlite-vfs", + "wasm-bindgen", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strands-metrics" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "clap", + "http", + "indicatif", + "octocrab", + "reqwest", + "rusqlite", + "serde", + "serde_json", + "serde_yaml", + "tokio", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +dependencies = [ + "fastrand", + "getrandom 0.4.1", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unit-prefix" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/community-dashboard/Cargo.toml b/community-dashboard/strands-metrics/Cargo.toml similarity index 100% rename from community-dashboard/Cargo.toml rename to community-dashboard/strands-metrics/Cargo.toml diff --git a/community-dashboard/src/aggregates.rs b/community-dashboard/strands-metrics/src/aggregates.rs similarity index 100% rename from community-dashboard/src/aggregates.rs rename to community-dashboard/strands-metrics/src/aggregates.rs diff --git a/community-dashboard/src/client.rs b/community-dashboard/strands-metrics/src/client.rs similarity index 100% rename from community-dashboard/src/client.rs rename to community-dashboard/strands-metrics/src/client.rs diff --git a/community-dashboard/src/db.rs b/community-dashboard/strands-metrics/src/db.rs similarity index 100% rename from community-dashboard/src/db.rs rename to community-dashboard/strands-metrics/src/db.rs diff --git a/community-dashboard/src/downloads.rs b/community-dashboard/strands-metrics/src/downloads.rs similarity index 82% rename from community-dashboard/src/downloads.rs rename to community-dashboard/strands-metrics/src/downloads.rs index cfc4e49..f89ea35 100644 --- a/community-dashboard/src/downloads.rs +++ b/community-dashboard/strands-metrics/src/downloads.rs @@ -2,7 +2,6 @@ use anyhow::{Context, Result}; use chrono::{Duration, Utc}; use rusqlite::{params, Connection}; use serde::Deserialize; -use std::collections::HashMap; // ============================================================================ // PyPI API Types @@ -19,11 +18,6 @@ struct PyPIDataPoint { downloads: i64, } -#[derive(Debug, Deserialize)] -struct PyPIVersionResponse { - data: HashMap>, -} - // ============================================================================ // npm API Types // ============================================================================ @@ -39,16 +33,6 @@ struct NpmDownloadPoint { downloads: i64, } -#[derive(Debug, Deserialize)] -struct NpmVersionsResponse { - versions: HashMap, // version -> tarball url -} - -#[derive(Debug, Deserialize)] -struct NpmPackageInfo { - time: HashMap, // version -> publish date -} - // ============================================================================ // Sync Functions // ============================================================================ @@ -247,41 +231,3 @@ pub fn load_repo_mappings(conn: &Connection, config: &PackagesConfig) -> Result< Ok(count) } -// ============================================================================ -// Query Helpers -// ============================================================================ - -pub fn get_total_downloads(conn: &Connection, package: &str, registry: &str) -> Result { - let total: i64 = conn.query_row( - "SELECT COALESCE(SUM(downloads), 0) FROM package_downloads - WHERE package = ?1 AND registry = ?2 AND version = 'total'", - params![package, registry], - |row| row.get(0), - )?; - Ok(total) -} - -pub fn get_downloads_by_date( - conn: &Connection, - package: &str, - registry: &str, - start_date: &str, - end_date: &str, -) -> Result> { - let mut stmt = conn.prepare( - "SELECT date, downloads FROM package_downloads - WHERE package = ?1 AND registry = ?2 AND version = 'total' - AND date >= ?3 AND date <= ?4 - ORDER BY date", - )?; - - let rows = stmt.query_map(params![package, registry, start_date, end_date], |row| { - Ok((row.get(0)?, row.get(1)?)) - })?; - - let mut results = Vec::new(); - for row in rows { - results.push(row?); - } - Ok(results) -} diff --git a/community-dashboard/src/goals.rs b/community-dashboard/strands-metrics/src/goals.rs similarity index 99% rename from community-dashboard/src/goals.rs rename to community-dashboard/strands-metrics/src/goals.rs index 83f20de..94995da 100644 --- a/community-dashboard/src/goals.rs +++ b/community-dashboard/strands-metrics/src/goals.rs @@ -23,6 +23,7 @@ impl Direction { } } + #[cfg(test)] fn default_warning_ratio(&self) -> f64 { match self { Direction::LowerIsBetter => 0.75, @@ -57,6 +58,7 @@ pub struct Goal { impl Goal { /// Calculate the warning threshold value + #[cfg(test)] pub fn warning_value(&self) -> f64 { let ratio = self.warning_ratio.unwrap_or_else(|| self.direction.default_warning_ratio()); self.value * ratio diff --git a/community-dashboard/src/main.rs b/community-dashboard/strands-metrics/src/main.rs similarity index 95% rename from community-dashboard/src/main.rs rename to community-dashboard/strands-metrics/src/main.rs index e1daf83..36b4d1e 100644 --- a/community-dashboard/src/main.rs +++ b/community-dashboard/strands-metrics/src/main.rs @@ -20,7 +20,7 @@ const ORG: &str = "strands-agents"; #[derive(Parser)] #[clap(author, version, about)] struct Cli { - #[clap(long, short, default_value = "metrics.db")] + #[clap(long, short, default_value = "../metrics.db")] db_path: PathBuf, #[clap(subcommand)] command: Commands, @@ -37,7 +37,7 @@ enum Commands { /// Load goals from YAML config file into the database. LoadGoals { /// Path to goals.yaml file - #[clap(default_value = "goals.yaml")] + #[clap(default_value = "../goals.yaml")] config_path: PathBuf, }, /// List all configured goals. @@ -45,7 +45,7 @@ enum Commands { /// Load team members into the database for dashboard queries. LoadTeam { /// Path to team.yaml config file - #[clap(default_value = "team.yaml")] + #[clap(default_value = "../team.yaml")] config_path: PathBuf, /// Comma-separated list of GitHub usernames (overrides config file) #[clap(long, value_delimiter = ',')] @@ -54,7 +54,7 @@ enum Commands { /// Sync package download stats from PyPI and npm. SyncDownloads { /// Path to packages.yaml config file - #[clap(long, default_value = "packages.yaml")] + #[clap(long, default_value = "../packages.yaml")] config_path: PathBuf, /// Number of days to fetch (default: 30) #[clap(long, default_value = "30")] @@ -63,7 +63,7 @@ enum Commands { /// Backfill historical download data (PyPI: ~180 days, npm: ~365 days). BackfillDownloads { /// Path to packages.yaml config file - #[clap(long, default_value = "packages.yaml")] + #[clap(long, default_value = "../packages.yaml")] config_path: PathBuf, }, } @@ -154,8 +154,8 @@ async fn main() -> Result<()> { Commands::ListGoals => { let all_goals = goals::list_goals(&conn)?; println!( - "{:<40} | {:>10} | {:<20} | {:<15} | {}", - "Metric", "Value", "Label", "Direction", "Warning Ratio" + "{:<40} | {:>10} | {:<20} | {:<15} | Warning Ratio", + "Metric", "Value", "Label", "Direction" ); println!("{}", "-".repeat(110)); for goal in all_goals { From 0b781571d962d6e203795116b52dba80245ab5bf Mon Sep 17 00:00:00 2001 From: Jonathan Segev Date: Sun, 15 Feb 2026 06:26:52 -0500 Subject: [PATCH 07/22] docs: Add Podman instructions to README --- community-dashboard/README.md | 37 ++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/community-dashboard/README.md b/community-dashboard/README.md index 7574313..8afba8d 100644 --- a/community-dashboard/README.md +++ b/community-dashboard/README.md @@ -50,7 +50,7 @@ community-dashboard/ ## Quick Start -### Local dev with auto-sync +### Local dev with auto-sync (Docker) Build the unified image that syncs GitHub data automatically: @@ -60,6 +60,41 @@ GITHUB_TOKEN=ghp_xxx docker compose -f docker/docker-compose.local.yaml up --bui Open [http://localhost:3000](http://localhost:3000). This builds the Rust CLI, runs an initial sync on startup, and schedules daily updates at 06:00 UTC via supercronic. +### Local dev with auto-sync (Podman) + +Podman works as a drop-in replacement. Build and run manually: + +```bash +# Build the image +podman build -t community-dashboard -f docker/Dockerfile . + +# Run the container +podman run -d --name community-dashboard \ + -p 3000:3000 \ + -e GITHUB_TOKEN=ghp_xxx \ + -v community-dashboard-data:/var/lib/grafana/data \ + community-dashboard +``` + +Or use `podman-compose` with the existing compose file: + +```bash +GITHUB_TOKEN=ghp_xxx podman-compose -f docker/docker-compose.local.yaml up --build +``` + +To persist data across container restarts, the named volume `community-dashboard-data` stores `metrics.db` at `/var/lib/grafana/data`. You can also bind-mount a local directory instead: + +```bash +mkdir -p docker/data +podman run -d --name community-dashboard \ + -p 3000:3000 \ + -e GITHUB_TOKEN=ghp_xxx \ + -v ./docker/data:/var/lib/grafana/data:Z \ + community-dashboard +``` + +The `:Z` suffix is needed on SELinux-enabled systems (Fedora, RHEL) to relabel the mount for container access. + ### Standalone CLI Build and run `strands-metrics` directly: From 77c0c12d699bf4f0dd56eeb206f3e6865c00b8b3 Mon Sep 17 00:00:00 2001 From: Jonathan Segev Date: Tue, 17 Feb 2026 00:30:52 -0500 Subject: [PATCH 08/22] fix(docker): Fix seed DB COPY for BuildKit compatibility --- community-dashboard/.gitignore | 5 +++-- community-dashboard/docker/Dockerfile | 9 +++++---- community-dashboard/docker/data/.gitkeep | 0 3 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 community-dashboard/docker/data/.gitkeep diff --git a/community-dashboard/.gitignore b/community-dashboard/.gitignore index 441f0a9..78b8f97 100644 --- a/community-dashboard/.gitignore +++ b/community-dashboard/.gitignore @@ -7,8 +7,9 @@ cdk/cdk.out/ cdk/dist/ cdk/.env -# Docker -docker/data/ +# Docker (ignore DB snapshots but keep the directory) +docker/data/* +!docker/data/.gitkeep # IDE .idea/ diff --git a/community-dashboard/docker/Dockerfile b/community-dashboard/docker/Dockerfile index 776065b..e4a32bd 100644 --- a/community-dashboard/docker/Dockerfile +++ b/community-dashboard/docker/Dockerfile @@ -50,10 +50,11 @@ RUN chmod +x /entrypoint.sh /usr/local/bin/sync-all.sh # Create the data directory for EFS / local mount RUN mkdir -p /var/lib/grafana/data -# Bundle a pre-built metrics.db so the first boot doesn't need a long backfill. -# The entrypoint will copy this to the EFS volume if no DB exists yet. -# The wildcard pattern makes this a no-op if the file doesn't exist. -COPY docker/data/metrics.d[b] /seed/ +# Optionally bundle a pre-built metrics.db so the first boot doesn't need +# a long backfill. Place metrics.db in docker/data/ before building. +# The entrypoint will copy it to the EFS volume if no DB exists yet. +RUN mkdir -p /seed +COPY docker/data/ /seed/ # Grafana configuration via environment variables ENV GF_INSTALL_PLUGINS=frser-sqlite-datasource diff --git a/community-dashboard/docker/data/.gitkeep b/community-dashboard/docker/data/.gitkeep new file mode 100644 index 0000000..e69de29 From 88c62aae7aa65880fc702a8c168dd477c175dd72 Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Wed, 25 Feb 2026 16:22:12 -0500 Subject: [PATCH 09/22] merge PR #31 dashboards + resolve conflicts with local changes --- .../cdk/lib/community-dashboard-stack.ts | 122 ++++++++++++------ community-dashboard/docker/Dockerfile | 2 +- community-dashboard/docker/entrypoint.sh | 12 ++ .../strands-metrics/src/aggregates.rs | 17 ++- 4 files changed, 104 insertions(+), 49 deletions(-) diff --git a/community-dashboard/cdk/lib/community-dashboard-stack.ts b/community-dashboard/cdk/lib/community-dashboard-stack.ts index 2d96771..0eb673c 100644 --- a/community-dashboard/cdk/lib/community-dashboard-stack.ts +++ b/community-dashboard/cdk/lib/community-dashboard-stack.ts @@ -2,11 +2,12 @@ import * as cdk from "aws-cdk-lib"; import * as ec2 from "aws-cdk-lib/aws-ec2"; import * as ecs from "aws-cdk-lib/aws-ecs"; import * as efs from "aws-cdk-lib/aws-efs"; -import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2"; +import * as apigwv2 from "aws-cdk-lib/aws-apigatewayv2"; import * as cloudfront from "aws-cdk-lib/aws-cloudfront"; import * as origins from "aws-cdk-lib/aws-cloudfront-origins"; import * as logs from "aws-cdk-lib/aws-logs"; import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"; +import * as servicediscovery from "aws-cdk-lib/aws-servicediscovery"; import { Construct } from "constructs"; import * as path from "path"; @@ -15,8 +16,6 @@ export class CommunityDashboardStack extends cdk.Stack { super(scope, id, props); // ── Secrets Manager ────────────────────────────────────────────────── - // The GitHub PAT must already exist in Secrets Manager as a plain-text - // secret. Pass the ARN via the GITHUB_SECRET_ARN env var or CDK context. const secretArn = process.env.GITHUB_SECRET_ARN ?? this.node.tryGetContext("githubSecretArn"); @@ -25,7 +24,7 @@ export class CommunityDashboardStack extends cdk.Stack { throw new Error( "GITHUB_SECRET_ARN environment variable or 'githubSecretArn' CDK context must be set.\n" + "Create the secret first:\n" + - ' aws secretsmanager create-secret --name strands-grafana/github-token --secret-string "ghp_xxx" --region us-west-2' + ' aws secretsmanager create-secret --name strands-grafana/github-token --secret-string "ghp_xxx" --region us-east-1' ); } @@ -63,7 +62,16 @@ export class CommunityDashboardStack extends cdk.Stack { }, }); - // ── ECS Cluster ───────────────────────────────────────────────────── + // ── ECS Cluster + Cloud Map namespace ─────────────────────────────── + const namespace = new servicediscovery.PrivateDnsNamespace( + this, + "Namespace", + { + name: "community-dashboard.local", + vpc, + } + ); + const cluster = new ecs.Cluster(this, "Cluster", { vpc, containerInsights: true, @@ -75,7 +83,6 @@ export class CommunityDashboardStack extends cdk.Stack { memoryLimitMiB: 1024, }); - // Mount EFS volume taskDef.addVolume({ name: "metrics-data", efsVolumeConfiguration: { @@ -88,7 +95,6 @@ export class CommunityDashboardStack extends cdk.Stack { }, }); - // Grant EFS access to the task role fileSystem.grant( taskDef.taskRole, "elasticfilesystem:ClientMount", @@ -96,15 +102,11 @@ export class CommunityDashboardStack extends cdk.Stack { "elasticfilesystem:ClientRootAccess" ); - // Container definition — built from the unified Dockerfile const container = taskDef.addContainer("grafana", { - image: ecs.ContainerImage.fromAsset( - path.join(__dirname, "../../"), - { - file: "docker/Dockerfile", - platform: cdk.aws_ecr_assets.Platform.LINUX_AMD64, - } - ), + image: ecs.ContainerImage.fromAsset(path.join(__dirname, "../../"), { + file: "docker/Dockerfile", + platform: cdk.aws_ecr_assets.Platform.LINUX_AMD64, + }), logging: ecs.LogDrivers.awsLogs({ streamPrefix: "community-dashboard", logRetention: logs.RetentionDays.TWO_WEEKS, @@ -131,63 +133,97 @@ export class CommunityDashboardStack extends cdk.Stack { readOnly: false, }); - // ── Fargate Service + ALB ─────────────────────────────────────────── + // ── Fargate Service with Cloud Map service discovery ──────────────── const service = new ecs.FargateService(this, "Service", { cluster, taskDefinition: taskDef, desiredCount: 1, assignPublicIp: false, platformVersion: ecs.FargatePlatformVersion.LATEST, + enableExecuteCommand: true, + cloudMapOptions: { + cloudMapNamespace: namespace, + name: "grafana", + containerPort: 3000, + dnsRecordType: servicediscovery.DnsRecordType.SRV, + }, }); - // Allow the service to reach EFS service.connections.allowTo(fileSystem, ec2.Port.tcp(2049), "EFS access"); - // Application Load Balancer - const alb = new elbv2.ApplicationLoadBalancer(this, "Alb", { - vpc, - internetFacing: true, + // ── API Gateway HTTP API + VPC Link ───────────────────────────────── + // No ALB needed — API Gateway connects directly to ECS via VPC Link. + // This avoids Epoxy/Riddler flagging a public-facing Grafana instance. + const vpcLink = new apigwv2.CfnVpcLink(this, "VpcLink", { + name: "community-dashboard-vpc-link", + subnetIds: vpc.privateSubnets.map((s) => s.subnetId), + securityGroupIds: [service.connections.securityGroups[0].securityGroupId], }); - const listener = alb.addListener("HttpListener", { - port: 80, + const httpApi = new apigwv2.CfnApi(this, "HttpApi", { + name: "community-dashboard-api", + protocolType: "HTTP", + description: "API Gateway for Community Dashboard (Grafana)", }); - listener.addTargets("GrafanaTarget", { - port: 3000, - protocol: elbv2.ApplicationProtocol.HTTP, - targets: [service], - healthCheck: { - path: "/api/health", - interval: cdk.Duration.seconds(30), - healthyThresholdCount: 2, - unhealthyThresholdCount: 3, - }, - deregistrationDelay: cdk.Duration.seconds(30), + // Integration: forward all requests to the Cloud Map service via VPC Link + const integration = new apigwv2.CfnIntegration(this, "Integration", { + apiId: httpApi.ref, + integrationType: "HTTP_PROXY", + integrationMethod: "ANY", + connectionType: "VPC_LINK", + connectionId: vpcLink.ref, + integrationUri: service.cloudMapService!.serviceArn, + payloadFormatVersion: "1.0", }); - // ── Outputs ───────────────────────────────────────────────────────── - // CloudFront distribution — provides HTTPS on *.cloudfront.net + new apigwv2.CfnRoute(this, "DefaultRoute", { + apiId: httpApi.ref, + routeKey: "$default", + target: `integrations/${integration.ref}`, + }); + + const stage = new apigwv2.CfnStage(this, "DefaultStage", { + apiId: httpApi.ref, + stageName: "$default", + autoDeploy: true, + }); + + // Allow API Gateway VPC Link to reach the ECS service + service.connections.allowFrom( + ec2.Peer.ipv4(vpc.vpcCidrBlock), + ec2.Port.tcp(3000), + "Allow API Gateway VPC Link" + ); + + // ── CloudFront ────────────────────────────────────────────────────── + // Extract the API Gateway domain from the endpoint URL + const apiDomain = cdk.Fn.select( + 2, + cdk.Fn.split("/", httpApi.attrApiEndpoint) + ); + const distribution = new cloudfront.Distribution(this, "Distribution", { defaultBehavior: { - origin: new origins.HttpOrigin(alb.loadBalancerDnsName, { - protocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY, + origin: new origins.HttpOrigin(apiDomain, { + protocolPolicy: cloudfront.OriginProtocolPolicy.HTTPS_ONLY, }), viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED, - originRequestPolicy: cloudfront.OriginRequestPolicy.ALL_VIEWER, + originRequestPolicy: cloudfront.OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER, allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL, }, }); + // ── Outputs ───────────────────────────────────────────────────────── new cdk.CfnOutput(this, "GrafanaUrl", { value: `https://${distribution.distributionDomainName}`, description: "Grafana dashboard URL (HTTPS via CloudFront)", }); - new cdk.CfnOutput(this, "AlbUrl", { - value: `http://${alb.loadBalancerDnsName}`, - description: "Grafana dashboard URL (ALB, HTTP only)", + new cdk.CfnOutput(this, "ApiGatewayUrl", { + value: httpApi.attrApiEndpoint, + description: "API Gateway endpoint URL", }); new cdk.CfnOutput(this, "EfsFileSystemId", { @@ -202,7 +238,7 @@ export class CommunityDashboardStack extends cdk.Stack { new cdk.CfnOutput(this, "CreateSecretCommand", { value: - 'aws secretsmanager create-secret --name strands-grafana/github-token --secret-string "ghp_xxx" --region us-west-2', + 'aws secretsmanager create-secret --name strands-grafana/github-token --secret-string "ghp_xxx" --region us-east-1', description: "Command to create the GitHub token secret (one-time)", }); } diff --git a/community-dashboard/docker/Dockerfile b/community-dashboard/docker/Dockerfile index e4a32bd..5deb433 100644 --- a/community-dashboard/docker/Dockerfile +++ b/community-dashboard/docker/Dockerfile @@ -22,7 +22,7 @@ FROM grafana/grafana:latest USER root # Install ca-certificates and curl for downloading supercronic -RUN apk add --no-cache ca-certificates curl +RUN apk add --no-cache ca-certificates curl sqlite # Install supercronic (cron replacement designed for containers) ARG SUPERCRONIC_VERSION=v0.2.43 diff --git a/community-dashboard/docker/entrypoint.sh b/community-dashboard/docker/entrypoint.sh index ecfffcb..318021b 100644 --- a/community-dashboard/docker/entrypoint.sh +++ b/community-dashboard/docker/entrypoint.sh @@ -48,6 +48,18 @@ echo "[entrypoint] Syncing package downloads..." strands-metrics --db-path "$DB_PATH" sync-downloads --config-path "$CONFIG_DIR/packages.yaml" || \ echo "[entrypoint] WARNING: Failed to sync downloads." +# ── One-time metrics recompute (set RECOMPUTE_METRICS=true to trigger) ─────── +if [ "${RECOMPUTE_METRICS:-false}" = "true" ]; then + echo "[entrypoint] RECOMPUTE_METRICS=true — wiping daily_metrics for full recalculation..." + sqlite3 "$DB_PATH" "DELETE FROM daily_metrics;" + echo "[entrypoint] daily_metrics cleared. Next sync will rebuild all aggregates." + if [ -n "$GITHUB_TOKEN" ]; then + echo "[entrypoint] Running sync + full recompute now..." + strands-metrics --db-path "$DB_PATH" sync || \ + echo "[entrypoint] WARNING: Recompute sync failed (will retry on next cron run)." + fi +fi + # ── Cron schedule ─────────────────────────────────────────────────────────── # Sync daily at 06:00 UTC. Output is forwarded to container stdout/stderr # via /proc/1/fd/1 so it shows up in docker logs / CloudWatch. diff --git a/community-dashboard/strands-metrics/src/aggregates.rs b/community-dashboard/strands-metrics/src/aggregates.rs index 5f01afb..9f3a437 100644 --- a/community-dashboard/strands-metrics/src/aggregates.rs +++ b/community-dashboard/strands-metrics/src/aggregates.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use chrono::{DateTime, Duration, NaiveDate, TimeZone, Utc}; +use chrono::{Duration, NaiveDate, NaiveTime, Utc}; use rusqlite::{params, Connection}; pub fn compute_metrics(conn: &Connection) -> Result<()> { @@ -10,11 +10,17 @@ pub fn compute_metrics(conn: &Connection) -> Result<()> { let start_date = match last_metric_date { Some(d) => NaiveDate::parse_from_str(&d, "%Y-%m-%d") - .map(|nd| Utc.from_utc_datetime(&nd.and_hms_opt(0, 0, 0).unwrap()) - Duration::days(3)) + .map(|nd| { + nd.and_time(NaiveTime::MIN) + .and_utc() + .checked_sub_signed(Duration::days(3)) + .unwrap() + }) .unwrap_or_else(|_| Utc::now()), - None => DateTime::parse_from_rfc3339("2010-01-01T00:00:00Z") + None => NaiveDate::from_ymd_opt(2025, 5, 1) .unwrap() - .with_timezone(&Utc), + .and_time(NaiveTime::MIN) + .and_utc(), }; let start_date_str = start_date.format("%Y-%m-%d").to_string(); @@ -56,8 +62,9 @@ pub fn compute_metrics(conn: &Connection) -> Result<()> { let now = Utc::now(); let num_days = (now - start_date).num_days(); + // Iterate newest-first so dashboards show current data ASAP for i in 0..=num_days { - let date = start_date + Duration::days(i); + let date = now - Duration::days(i); let date_str = date.format("%Y-%m-%d").to_string(); conn.execute( From f0017c7c74f9f66373044d3b5bc6a4634116a1a9 Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Wed, 25 Feb 2026 16:23:20 -0500 Subject: [PATCH 10/22] cleanup: remove old dashboard files moved to subfolders --- .../provisioning/dashboards/health.json | 12577 ---------------- .../provisioning/dashboards/triage.json | 676 - .../strands-metrics/Cargo.lock.bak | 2592 ---- 3 files changed, 15845 deletions(-) delete mode 100644 community-dashboard/provisioning/dashboards/health.json delete mode 100644 community-dashboard/provisioning/dashboards/triage.json delete mode 100644 community-dashboard/strands-metrics/Cargo.lock.bak diff --git a/community-dashboard/provisioning/dashboards/health.json b/community-dashboard/provisioning/dashboards/health.json deleted file mode 100644 index 1508b03..0000000 --- a/community-dashboard/provisioning/dashboards/health.json +++ /dev/null @@ -1,12577 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 4, - "links": [], - "panels": [ - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 100, - "panels": [], - "title": "Volume", - "type": "row" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 1 - }, - "id": 11, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_prs_count as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_prs_count as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Total Open PRs", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "Total count of open pull requests." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 1 - }, - "id": 20, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Total Open Issues", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "Total count of open issues (excluding pull requests)." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1, - "scaleDistribution": { - "type": "linear" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 8 - }, - "id": 23, - "options": { - "barRadius": 0, - "barWidth": 0.97, - "fullHighlight": false, - "groupWidth": 0.7, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "orientation": "auto", - "showValue": "never", - "stacking": "normal", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 100 - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_opened as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_opened as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "PRs Opened (Daily)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "barchart", - "description": "Number of new pull requests opened per day." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1, - "scaleDistribution": { - "type": "linear" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 8 - }, - "id": 2, - "options": { - "barRadius": 0, - "barWidth": 0.97, - "fullHighlight": false, - "groupWidth": 0.7, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "orientation": "auto", - "showValue": "never", - "stacking": "normal", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 100 - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Issues Opened (Daily)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "barchart", - "description": "Number of new issues opened per day." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1, - "scaleDistribution": { - "type": "linear" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 16 - }, - "id": 1, - "options": { - "barRadius": 0, - "barWidth": 0.97, - "fullHighlight": false, - "groupWidth": 0.7, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "orientation": "auto", - "showValue": "never", - "stacking": "normal", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 100 - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "PRs Merged (Daily)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "barchart", - "description": "Number of pull requests merged per day." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1, - "scaleDistribution": { - "type": "linear" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 16 - }, - "id": 3, - "options": { - "barRadius": 0, - "barWidth": 0.97, - "fullHighlight": false, - "groupWidth": 0.7, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "orientation": "auto", - "showValue": "never", - "stacking": "normal", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 100 - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Issues Closed (Daily)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "barchart", - "description": "Number of issues closed per day." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": true, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 24, - "x": 0, - "y": 24 - }, - "id": 16, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_items_count - LAG(open_items_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_items_count - LAG(open_items_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Backlog Growth (Week-over-Week)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "Week-over-week change in total open items (issues + PRs). Positive = backlog growing, negative = backlog shrinking." - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 34 - }, - "id": 102, - "panels": [], - "title": "Quality", - "type": "row" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "percent" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 35 - }, - "id": 13, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "CI Failure Rate (7-Day Avg)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "7-day rolling average of CI failure rate: (failed CI runs / total CI runs) \u00d7 100%. Shows percentage of CI runs that failed." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "percent", - "min": 0, - "max": 100 - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 35 - }, - "id": 15, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN (${repo:singlequote})\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "PR Acceptance Rate (30-Day Avg)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "30-day rolling average of PR acceptance rate: (PRs merged / PRs opened) \u00d7 100%. Shows what percentage of opened PRs ultimately get merged." - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 41 - }, - "id": 101, - "panels": [], - "title": "Speed", - "type": "row" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "h" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 42 - }, - "id": 21, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND time_to_first_response > 0\nORDER BY time ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND time_to_first_response > 0\nORDER BY time ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Time to First Response", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "Average hours from issue/PR creation to first comment or review. 30-day rolling average." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "h" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 42 - }, - "id": 22, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND avg_issue_resolution_time > 0\nORDER BY time ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND avg_issue_resolution_time > 0\nORDER BY time ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Issue Resolution Time", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "Average hours from issue creation to closure. 30-day rolling average." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 43 - }, - "id": 14, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Code Churn (7-Day Avg, <10k)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "7-day rolling average of total lines changed per day (additions + deletions). Filters out days with >10,000 line changes to exclude anomalies like generated code, large imports, or bulk formatting changes." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "h" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 50 - }, - "id": 17, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", - "queryType": "table", - "rawQueryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Cycle Time (PR Open \u2192 Merge, 14-Day Avg)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "Average hours from PR creation to merge, split by internal vs external contributors. 14-day rolling average." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "h" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 50 - }, - "id": 20, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", - "queryType": "table", - "rawQueryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Time to First Review (14-Day Avg)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "Average hours from PR creation to first review. 14-day rolling average." - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 51 - }, - "id": 103, - "panels": [], - "title": "Community", - "type": "row" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 52 - }, - "id": 12, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Total Stars", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "Cumulative count of GitHub stars across selected repositories, tracked over time." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 52 - }, - "id": 10, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", - "queryType": "table", - "rawQueryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Weekly Active External Contributors", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "Count of unique external contributors (non-team members: not OWNER/MEMBER/COLLABORATOR) who created PRs in the rolling 7-day window ending on each date." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - } - ] - }, - "unit": "percent", - "min": 0, - "max": 100 - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 60 - }, - "id": 18, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "External Contribution Rate (30-Day Avg)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries", - "description": "30-day rolling average percentage of merged PRs that were authored by external contributors (non-team members)." - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1, - "scaleDistribution": { - "type": "linear" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 60 - }, - "id": 9, - "options": { - "barRadius": 0, - "barWidth": 0.97, - "fullHighlight": false, - "groupWidth": 0.7, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "orientation": "auto", - "showValue": "never", - "stacking": "normal", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 100 - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", - "queryType": "table", - "rawQueryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "PRs Closed Without Merging (Daily)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "barchart", - "description": "Daily count of PRs closed without being merged (rejected PRs), split by Internal (team) vs External (community) contributors." - } - ], - "preload": false, - "schemaVersion": 42, - "tags": [], - "templating": { - "list": [ - { - "allowCustomValue": false, - "current": { - "text": [ - "agent-builder", - "agent-sop", - "docs", - "sdk-python", - "sdk-typescript", - "tools" - ], - "value": [ - "agent-builder", - "agent-sop", - "docs", - "sdk-python", - "sdk-typescript", - "tools" - ] - }, - "definition": "SELECT DISTINCT repo FROM daily_metrics", - "description": "", - "includeAll": true, - "multi": true, - "name": "repo", - "options": [], - "query": "SELECT DISTINCT repo FROM daily_metrics", - "refresh": 1, - "regex": "", - "sort": 1, - "type": "query" - } - ] - }, - "time": { - "from": "now-30d", - "to": "now" - }, - "timepicker": {}, - "timezone": "browser", - "title": "Strands Health", - "uid": "adj9pgt", - "version": 2 -} \ No newline at end of file diff --git a/community-dashboard/provisioning/dashboards/triage.json b/community-dashboard/provisioning/dashboards/triage.json deleted file mode 100644 index 24b8c76..0000000 --- a/community-dashboard/provisioning/dashboards/triage.json +++ /dev/null @@ -1,676 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 0, - "links": [], - "panels": [ - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "footer": { - "reducers": [] - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Title" - }, - "properties": [ - { - "id": "links", - "value": [ - { - "title": "Open on GitHub", - "url": "${__data.fields.URL}" - } - ] - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "URL" - }, - "properties": [ - { - "id": "custom.hideFrom.viz", - "value": true - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Status" - }, - "properties": [ - { - "id": "custom.width", - "value": 118 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Days Open" - }, - "properties": [ - { - "id": "custom.width", - "value": 87 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Author" - }, - "properties": [ - { - "id": "custom.width", - "value": 148 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Repo" - }, - "properties": [ - { - "id": "custom.width", - "value": 161 - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 22, - "x": 1, - "y": 0 - }, - "id": 1, - "options": { - "cellHeight": "sm", - "showHeader": true, - "sortBy": [ - { - "desc": true, - "displayName": "Days Open" - } - ] - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "queryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n CASE \n WHEN r.state = 'APPROVED' THEN 'Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN 'Changes Requested' \n ELSE 'Needs Review' \n END as \"Status\", \n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\" \nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \nORDER BY \"Days Open\" DESC", - "queryType": "table", - "rawQueryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n CASE \n WHEN r.state = 'APPROVED' THEN 'Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN 'Changes Requested' \n ELSE 'Needs Review' \n END as \"Status\", \n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\" \nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN (${repo:singlequote}) \nORDER BY \"Days Open\" DESC", - "refId": "A", - "timeColumns": ["time", "ts"] - } - ], - "title": "Team PRs", - "type": "table" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "footer": { - "reducers": [] - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Title" - }, - "properties": [ - { - "id": "links", - "value": [ - { - "title": "Open on GitHub", - "url": "${__data.fields.URL}" - } - ] - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "URL" - }, - "properties": [ - { - "id": "custom.hideFrom.viz", - "value": true - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Status" - }, - "properties": [ - { - "id": "custom.width", - "value": 118 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Days Open" - }, - "properties": [ - { - "id": "custom.width", - "value": 87 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Author" - }, - "properties": [ - { - "id": "custom.width", - "value": 148 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Repo" - }, - "properties": [ - { - "id": "custom.width", - "value": 161 - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 22, - "x": 1, - "y": 8 - }, - "id": 2, - "options": { - "cellHeight": "sm", - "showHeader": true, - "sortBy": [ - { - "desc": true, - "displayName": "Days Open" - } - ] - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n CASE \n WHEN r.state = 'APPROVED' THEN 'Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN 'Changes Requested' \n ELSE 'Needs Review' \n END as \"Status\", \n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\" \nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN (${repo:singlequote}) \nORDER BY \"Days Open\" DESC", - "queryType": "table", - "rawQueryText": "SELECT \n p.repo as \"Repo\", \n p.author as \"Author\", \n p.title as \"Title\", \n json_extract(p.data, '$.html_url') as \"URL\",\n CASE \n WHEN r.state = 'APPROVED' THEN 'Approved' \n WHEN r.state = 'CHANGES_REQUESTED' THEN 'Changes Requested' \n ELSE 'Needs Review' \n END as \"Status\", \n CAST((julianday('now') - julianday(p.created_at)) as INTEGER) as \"Days Open\" \nFROM pull_requests p \nLEFT JOIN (\n SELECT repo, pr_number, state FROM pr_reviews r1 \n WHERE submitted_at = (SELECT MAX(submitted_at) FROM pr_reviews r2 WHERE r2.pr_number = r1.pr_number AND r2.repo = r1.repo)\n) r ON p.repo = r.repo AND p.number = r.pr_number \nWHERE p.state = 'open' \n AND json_extract(p.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n AND p.repo IN (${repo:singlequote}) \nORDER BY \"Days Open\" DESC", - "refId": "A" - } - ], - "title": "Community PRs (External)", - "type": "table" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "footer": { - "reducers": [] - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Title" - }, - "properties": [ - { - "id": "links", - "value": [ - { - "title": "Open on GitHub", - "url": "${__data.fields.URL}" - } - ] - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "URL" - }, - "properties": [ - { - "id": "custom.hideFrom.viz", - "value": true - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Comments" - }, - "properties": [ - { - "id": "custom.width", - "value": 90 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Repo" - }, - "properties": [ - { - "id": "custom.width", - "value": 160 - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 22, - "x": 1, - "y": 16 - }, - "id": 3, - "options": { - "cellHeight": "sm", - "showHeader": true, - "sortBy": [ - { - "desc": true, - "displayName": "Comments" - } - ] - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n repo as \"Repo\", \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.comments') as \"Comments\" \nFROM issues \nWHERE state = 'open' AND json_extract(data, '$.milestone') IS NULL AND repo IN (${repo:singlequote}) \nORDER BY created_at ASC", - "queryType": "table", - "rawQueryText": "SELECT \n repo as \"Repo\", \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.comments') as \"Comments\" \nFROM issues \nWHERE state = 'open' AND json_extract(data, '$.milestone') IS NULL AND repo IN (${repo:singlequote}) \nORDER BY created_at ASC", - "refId": "A" - } - ], - "title": "Issues Needing Triage", - "type": "table" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "footer": { - "reducers": [] - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Title" - }, - "properties": [ - { - "id": "links", - "value": [ - { - "title": "Open on GitHub", - "url": "${__data.fields.URL}" - } - ] - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "URL" - }, - "properties": [ - { - "id": "custom.hideFrom.viz", - "value": true - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Upvotes" - }, - "properties": [ - { - "id": "custom.width", - "value": 80 - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 1, - "y": 24 - }, - "id": 4, - "options": { - "cellHeight": "sm", - "showHeader": true, - "sortBy": [ - { - "desc": true, - "displayName": "Upvotes" - } - ] - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.reactions.\"+1\"') as \"Upvotes\" \nFROM issues WHERE state = 'open' AND repo IN (${repo:singlequote}) \nORDER BY \"Upvotes\" DESC LIMIT 20", - "queryType": "table", - "rawQueryText": "SELECT \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.reactions.\"+1\"') as \"Upvotes\" \nFROM issues WHERE state = 'open' AND repo IN (${repo:singlequote}) \nORDER BY \"Upvotes\" DESC LIMIT 20", - "refId": "A", - "timeColumns": ["time", "ts"] - } - ], - "title": "Top Upvoted Issues", - "type": "table" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "footer": { - "reducers": [] - }, - "inspect": false - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Title" - }, - "properties": [ - { - "id": "links", - "value": [ - { - "title": "Open on GitHub", - "url": "${__data.fields.URL}" - } - ] - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "URL" - }, - "properties": [ - { - "id": "custom.hideFrom.viz", - "value": true - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Comments" - }, - "properties": [ - { - "id": "custom.width", - "value": 80 - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 10, - "x": 13, - "y": 24 - }, - "id": 5, - "options": { - "cellHeight": "sm", - "showHeader": true, - "sortBy": [ - { - "desc": true, - "displayName": "Comments" - } - ] - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.comments') as \"Comments\" \nFROM issues WHERE state = 'open' AND repo IN (${repo:singlequote}) \nORDER BY \"Comments\" DESC LIMIT 20", - "queryType": "table", - "rawQueryText": "SELECT \n title as \"Title\", \n json_extract(data, '$.html_url') as \"URL\",\n json_extract(data, '$.comments') as \"Comments\" \nFROM issues WHERE state = 'open' AND repo IN (${repo:singlequote}) \nORDER BY \"Comments\" DESC LIMIT 20", - "refId": "A" - } - ], - "title": "Most Discussed Issues", - "type": "table" - } - ], - "preload": false, - "schemaVersion": 42, - "tags": [], - "templating": { - "list": [ - { - "allowCustomValue": false, - "current": { - "text": ["All"], - "value": ["$__all"] - }, - "definition": "SELECT DISTINCT repo FROM daily_metrics", - "includeAll": true, - "multi": true, - "name": "repo", - "options": [], - "query": "SELECT DISTINCT repo FROM daily_metrics", - "refresh": 1, - "regex": "", - "sort": 1, - "type": "query" - } - ] - }, - "time": { - "from": "now-30d", - "to": "now" - }, - "timepicker": {}, - "timezone": "browser", - "title": "Strands Triage", - "uid": "advqxqk", - "version": 4 -} diff --git a/community-dashboard/strands-metrics/Cargo.lock.bak b/community-dashboard/strands-metrics/Cargo.lock.bak deleted file mode 100644 index 626940c..0000000 --- a/community-dashboard/strands-metrics/Cargo.lock.bak +++ /dev/null @@ -1,2592 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - -[[package]] -name = "anstyle-parse" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.61.2", -] - -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - -[[package]] -name = "arc-swap" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" -dependencies = [ - "rustversion", -] - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - -[[package]] -name = "bitflags" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" - -[[package]] -name = "bytes" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" - -[[package]] -name = "camino" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" -dependencies = [ - "serde_core", -] - -[[package]] -name = "cargo-platform" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87a0c0e6148f11f01f32650a2ea02d532b2ad4e81d8bd41e6e565b5adc5e6082" -dependencies = [ - "serde", - "serde_core", -] - -[[package]] -name = "cargo_metadata" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "cc" -version = "1.2.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "chrono" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link", -] - -[[package]] -name = "clap" -version = "4.5.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" - -[[package]] -name = "colorchoice" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" - -[[package]] -name = "console" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" -dependencies = [ - "encode_unicode", - "libc", - "once_cell", - "unicode-width", - "windows-sys 0.61.2", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", - "spki", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" -dependencies = [ - "curve25519-dalek", - "ed25519", - "serde", - "sha2", - "subtle", - "zeroize", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "hkdf", - "pem-rfc7468", - "pkcs8", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "encode_unicode" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-executor" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" - -[[package]] -name = "futures-macro" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" - -[[package]] -name = "futures-task" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" - -[[package]] -name = "futures-util" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "foldhash", -] - -[[package]] -name = "hashlink" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" -dependencies = [ - "hashbrown", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "http" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" -dependencies = [ - "bytes", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "hyper" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "http", - "http-body", - "httparse", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http", - "hyper", - "hyper-util", - "log", - "rustls", - "rustls-native-certs", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-timeout" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" -dependencies = [ - "hyper", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "libc", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "icu_collections" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - -[[package]] -name = "icu_properties" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" - -[[package]] -name = "icu_provider" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indicatif" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" -dependencies = [ - "console", - "portable-atomic", - "unicode-width", - "unit-prefix", - "web-time", -] - -[[package]] -name = "iri-string" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[package]] -name = "itoa" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" - -[[package]] -name = "js-sys" -version = "0.3.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e709f3e3d22866f9c25b3aff01af289b18422cc8b4262fb19103ee80fe513d" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "jsonwebtoken" -version = "10.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1" -dependencies = [ - "base64", - "ed25519-dalek", - "getrandom", - "hmac", - "js-sys", - "p256", - "p384", - "pem", - "rand", - "rsa", - "serde", - "serde_json", - "sha2", - "signature", - "simple_asn1", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "libc" -version = "0.2.182" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" - -[[package]] -name = "libm" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" - -[[package]] -name = "libsqlite3-sys" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b4103cffefa72eb8428cb6b47d6627161e51c2739fc5e3b734584157bc642a" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "litemap" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "mio" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", -] - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-bigint-dig" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" -dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-conv" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "octocrab" -version = "0.49.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89f6f72d7084a80bf261bb6b6f83bd633323d5633d5ec7988c6c95b20448b2b5" -dependencies = [ - "arc-swap", - "async-trait", - "base64", - "bytes", - "cargo_metadata", - "cfg-if", - "chrono", - "either", - "futures", - "futures-util", - "getrandom", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-timeout", - "hyper-util", - "jsonwebtoken", - "once_cell", - "percent-encoding", - "pin-project", - "secrecy", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "snafu", - "tokio", - "tower", - "tower-http", - "tracing", - "url", - "web-time", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - -[[package]] -name = "openssl-probe" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", -] - -[[package]] -name = "p384" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", -] - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - -[[package]] -name = "pem" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" -dependencies = [ - "base64", - "serde_core", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "portable-atomic" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" - -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rsa" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core", - "signature", - "spki", - "subtle", - "zeroize", -] - -[[package]] -name = "rsqlite-vfs" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a1f2315036ef6b1fbacd1972e8ee7688030b0a2121edfc2a6550febd41574d" -dependencies = [ - "hashbrown", - "thiserror", -] - -[[package]] -name = "rusqlite" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c93dd1c9683b438c392c492109cb702b8090b2bfc8fed6f6e4eb4523f17af3" -dependencies = [ - "bitflags", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", - "sqlite-wasm-rs", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustls" -version = "0.23.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" -dependencies = [ - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pki-types" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" - -[[package]] -name = "schannel" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "secrecy" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" -dependencies = [ - "zeroize", -] - -[[package]] -name = "security-framework" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" -dependencies = [ - "serde", - "serde_core", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" -dependencies = [ - "itoa", - "serde", - "serde_core", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "simple_asn1" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror", - "time", -] - -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "snafu" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2" -dependencies = [ - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "socket2" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "sqlite-wasm-rs" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4206ed3a67690b9c29b77d728f6acc3ce78f16bf846d83c94f76400320181b" -dependencies = [ - "cc", - "js-sys", - "rsqlite-vfs", - "wasm-bindgen", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "strands-metrics" -version = "0.1.0" -dependencies = [ - "anyhow", - "chrono", - "clap", - "http", - "indicatif", - "octocrab", - "rusqlite", - "serde", - "serde_json", - "tokio", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "time" -version = "0.3.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde_core", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" - -[[package]] -name = "time-macros" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.49.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" -dependencies = [ - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tower" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" -dependencies = [ - "bitflags", - "bytes", - "futures-util", - "http", - "http-body", - "iri-string", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unicode-width" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" - -[[package]] -name = "unit-prefix" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", - "serde_derive", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasm-bindgen" -version = "0.2.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1adf1535672f5b7824f817792b1afd731d7e843d2d04ec8f27e8cb51edd8ac" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e638317c08b21663aed4d2b9a2091450548954695ff4efa75bff5fa546b3b1" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c64760850114d03d5f65457e96fc988f11f01d38fbaa51b254e4ab5809102af" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60eecd4fe26177cfa3339eb00b4a36445889ba3ad37080c2429879718e20ca41" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - -[[package]] -name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "yoke" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" From 53fdda108809b76591b1f5adc98a2044dfe4ee2b Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Thu, 26 Feb 2026 17:17:25 -0500 Subject: [PATCH 11/22] feat: precalculate contributor aggregate metrics --- .../dashboards/general/health.json | 8 ++--- .../strands-metrics/src/aggregates.rs | 30 +++++++++++++++++++ community-dashboard/strands-metrics/src/db.rs | 14 +++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/community-dashboard/provisioning/dashboards/general/health.json b/community-dashboard/provisioning/dashboards/general/health.json index 711ab59..e0ec7ae 100644 --- a/community-dashboard/provisioning/dashboards/general/health.json +++ b/community-dashboard/provisioning/dashboards/general/health.json @@ -3359,9 +3359,9 @@ "pluginVersion": "12.3.1", "targets": [ { - "queryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "queryText": "SELECT\n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n weekly_community_contributors as value\nFROM daily_metrics\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", "queryType": "table", - "rawQueryText": "WITH weekly_contributors AS (\n SELECT \n date(created_at) as pr_date,\n repo,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n d.repo as metric,\n (\n SELECT COUNT(DISTINCT wc.author)\n FROM weekly_contributors wc\n WHERE wc.repo = d.repo\n AND wc.pr_date > date(d.date, '-7 days')\n AND wc.pr_date <= d.date\n ) as value\nFROM daily_metrics d\nWHERE d.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nORDER BY d.date ASC", + "rawQueryText": "SELECT\n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n weekly_community_contributors as value\nFROM daily_metrics\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", "refId": "A", "timeColumns": [ "time", @@ -11357,9 +11357,9 @@ }, "targets": [ { - "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\ndaily_new AS (\n SELECT \n first_pr_date as date,\n COUNT(*) as new_contributors\n FROM first_contributions\n GROUP BY first_pr_date\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n (SELECT SUM(new_contributors) FROM daily_new dn WHERE dn.date <= d.date) as value\nFROM daily_metrics d\nWHERE CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nGROUP BY d.date\nORDER BY d.date ASC", + "queryText": "SELECT\n CAST(strftime('%s', date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n cumulative_community_contributors as value\nFROM daily_metrics\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date\nORDER BY date ASC", "queryType": "table", - "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\ndaily_new AS (\n SELECT \n first_pr_date as date,\n COUNT(*) as new_contributors\n FROM first_contributions\n GROUP BY first_pr_date\n)\nSELECT \n CAST(strftime('%s', d.date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n (SELECT SUM(new_contributors) FROM daily_new dn WHERE dn.date <= d.date) as value\nFROM daily_metrics d\nWHERE CAST(strftime('%s', d.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', d.date) as INTEGER) <= $__to / 1000\nGROUP BY d.date\nORDER BY d.date ASC", + "rawQueryText": "SELECT\n CAST(strftime('%s', date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n cumulative_community_contributors as value\nFROM daily_metrics\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date\nORDER BY date ASC", "refId": "A", "timeColumns": [ "time", diff --git a/community-dashboard/strands-metrics/src/aggregates.rs b/community-dashboard/strands-metrics/src/aggregates.rs index 9f3a437..52da7b1 100644 --- a/community-dashboard/strands-metrics/src/aggregates.rs +++ b/community-dashboard/strands-metrics/src/aggregates.rs @@ -213,6 +213,36 @@ pub fn compute_metrics(conn: &Connection) -> Result<()> { WHERE date = ?1", params![date_str], )?; + + // Weekly community contributors (distinct external PR authors in 7-day window) + conn.execute( + "UPDATE daily_metrics + SET weekly_community_contributors = ( + SELECT COUNT(DISTINCT author) + FROM pull_requests + WHERE repo = daily_metrics.repo + AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') + AND date(created_at) > date(daily_metrics.date, '-7 days') + AND date(created_at) <= date(daily_metrics.date) + ) + WHERE date = ?1", + params![date_str], + )?; + + // Cumulative community contributors (running total of first-time external authors) + conn.execute( + "UPDATE daily_metrics + SET cumulative_community_contributors = ( + SELECT COUNT(DISTINCT author) + FROM pull_requests + WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') + AND author NOT LIKE '%[bot]%' + AND author NOT IN ('strands-agent', 'dependabot') + AND date(created_at) <= date(daily_metrics.date) + ) + WHERE date = ?1", + params![date_str], + )?; } // Cleanup temp table diff --git a/community-dashboard/strands-metrics/src/db.rs b/community-dashboard/strands-metrics/src/db.rs index c150b98..dc711aa 100644 --- a/community-dashboard/strands-metrics/src/db.rs +++ b/community-dashboard/strands-metrics/src/db.rs @@ -153,6 +153,9 @@ pub fn init_db>(path: P) -> Result { time_to_merge_internal REAL DEFAULT 0, time_to_merge_external REAL DEFAULT 0, + weekly_community_contributors INTEGER DEFAULT 0, + cumulative_community_contributors INTEGER DEFAULT 0, + PRIMARY KEY (date, repo) )", [], @@ -206,5 +209,16 @@ pub fn init_db>(path: P) -> Result { [], )?; + // ── Migrations for existing databases ────────────────────────────── + // ALTER TABLE is idempotent-safe: we ignore "duplicate column" errors. + let _ = conn.execute( + "ALTER TABLE daily_metrics ADD COLUMN weekly_community_contributors INTEGER DEFAULT 0", + [], + ); + let _ = conn.execute( + "ALTER TABLE daily_metrics ADD COLUMN cumulative_community_contributors INTEGER DEFAULT 0", + [], + ); + Ok(conn) } From 8682de2ab947edd44c82d63921887e959f26c5aa Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Thu, 26 Feb 2026 21:10:31 -0500 Subject: [PATCH 12/22] feat(community-dashboard): add agents.md --- community-dashboard/AGENTS.md | 237 ++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 community-dashboard/AGENTS.md diff --git a/community-dashboard/AGENTS.md b/community-dashboard/AGENTS.md new file mode 100644 index 0000000..8814205 --- /dev/null +++ b/community-dashboard/AGENTS.md @@ -0,0 +1,237 @@ +# Project Overview + +Community Dashboard is a GitHub metrics collection and visualization +platform for the `strands-agents` open-source organization. A Rust CLI +(`strands-metrics`) pulls data from GitHub, PyPI, and npm into a SQLite +database; Grafana renders seven pre-built dashboards across three +folders (General, SDKs, Operations). The stack runs locally via Docker +Compose or deploys to AWS with CDK (Fargate + EFS + CloudFront). + +## Repository Structure + +- `strands-metrics/` — Rust CLI that syncs GitHub/PyPI/npm data into + SQLite and computes daily aggregate metrics. +- `docker/` — Dockerfile (multi-stage: Rust build → Grafana image), + Compose file, entrypoint, and daily sync script. +- `provisioning/` — Grafana provisioning configs: datasource + (SQLite) and seven dashboard JSON files in three folders. +- `cdk/` — AWS CDK stack (TypeScript): VPC, ECS Fargate, EFS, + API Gateway, CloudFront. +- `goals.yaml` — Goal thresholds shown as lines on Health dashboard. +- `team.yaml` — Team members tracked in Team Performance dashboard. +- `packages.yaml` — Repo-to-registry mappings for download tracking. + +## Build & Development Commands + +### Local development (Docker) + +```bash +# Build and run with auto-sync (opens at http://localhost:3000) +GITHUB_TOKEN=ghp_xxx docker compose \ + -f docker/docker-compose.local.yaml up --build +``` + +### Standalone Rust CLI + +```bash +cd strands-metrics + +# Build +cargo build --release + +# Incremental GitHub sync (PRs, issues, stars, commits, CI, reviews) +GITHUB_TOKEN=ghp_xxx cargo run --release -- sync + +# Garbage-collect stale open items +GITHUB_TOKEN=ghp_xxx cargo run --release -- sweep + +# Sync recent PyPI/npm downloads (default 30 days) +cargo run --release -- sync-downloads + +# Backfill historical downloads (PyPI ~180d, npm ~365d) +cargo run --release -- backfill-downloads + +# Load goal thresholds / team members +cargo run --release -- load-goals +cargo run --release -- load-team + +# Ad-hoc SQL query +cargo run --release -- query "SELECT repo, COUNT(*) FROM pull_requests GROUP BY repo" +``` + +### CDK deployment + +```bash +cd cdk +cp .env.example .env # set GITHUB_SECRET_ARN +npm install +npx cdk deploy +``` + +### Lint / format (Rust) + +```bash +cd strands-metrics +cargo fmt --check +cargo clippy -- -D warnings +``` + +### CDK type-check + +```bash +cd cdk +npx tsc --noEmit +``` + +## Code Style & Conventions + +- Rust edition 2021; format with `cargo fmt`, lint with `cargo clippy`. +- CDK is TypeScript; standard `tsc` strict mode. +- Grafana dashboards are provisioned as JSON files under + `provisioning/dashboards/`. Edit JSON directly or export from + Grafana UI and commit. +- YAML configs (`goals.yaml`, `team.yaml`, `packages.yaml`) use + lowercase-snake_case keys. +- Shell scripts use `#!/bin/sh`, `set -e`, and log with bracketed + prefixes like `[entrypoint]` or `[sync-all]`. + +> TODO: No commit-message template is defined. Consider adopting +> Conventional Commits (`feat:`, `fix:`, `chore:`). + +## Architecture Notes + +``` +┌──────────────┐ ┌──────────────┐ ┌──────────────┐ +│ GitHub API │ │ PyPI Stats │ │ npm Registry │ +└──────┬───────┘ └──────┬───────┘ └──────┬───────┘ + │ │ │ + ▼ ▼ ▼ + ┌─────────────────────────────────────────┐ + │ strands-metrics CLI (Rust) │ + │ client.rs │ downloads.rs │ goals.rs │ + │ db.rs │ aggregates.rs │ + └──────────────────┬──────────────────────┘ + │ + ▼ + ┌───────────────┐ + │ metrics.db │ + │ (SQLite) │ + └───────┬───────┘ + │ + ▼ + ┌───────────────┐ + │ Grafana │ + │ (SQLite plugin)│ + └───────┬───────┘ + │ + ┌─────────────┼─────────────┐ + ▼ ▼ ▼ + General/ SDKs/ Operations/ + executive python-sdk team + health typescript-sdk triage + evals +``` + +### Rust modules + +| Module | Responsibility | +|---|---| +| `main.rs` | CLI entry point (clap), dispatches subcommands | +| `client.rs` | GitHub API client via octocrab | +| `db.rs` | SQLite schema init and migrations | +| `downloads.rs` | PyPI / npm download stat fetching | +| `goals.rs` | Goal thresholds and team member management | +| `aggregates.rs` | Daily metric computation from raw data | + +### AWS deployment path + +``` +CloudFront (HTTPS) + → API Gateway HTTP API (VPC Link) + → ECS Fargate (0.5 vCPU / 1 GB) + → Grafana + strands-metrics + → EFS (metrics.db, RETAIN policy) +``` + +Secrets Manager holds the GitHub PAT. Supercronic runs the daily +sync inside the container at 06:00 UTC. + +## Testing Strategy + +> TODO: No unit or integration tests exist for the Rust CLI. +> Consider adding tests for `aggregates.rs` computations and +> `goals.rs` YAML parsing. + +The GitHub Actions workflow (`.github/workflows/community-dashboard.yaml`) +runs daily at 06:00 UTC as a de-facto integration test: + +1. `cargo run --release -- sync` +2. `cargo run --release -- sweep` +3. `cargo run --release -- sync-downloads` +4. `cargo run --release -- load-goals` +5. `cargo run --release -- load-team` +6. Commits updated `metrics.db` back to the repo. + +Required secret: `METRICS_PAT` (GitHub PAT with org read access). + +## Security & Compliance + +- `GITHUB_TOKEN` is the only secret; never commit it. + - Locally: pass via env var or `.env` file (gitignored). + - AWS: stored in Secrets Manager, injected into ECS via CDK. + - CI: stored as `METRICS_PAT` GitHub Actions secret. +- Grafana runs in anonymous viewer-only mode + (`GF_AUTH_ANONYMOUS_ENABLED=true`, `GF_AUTH_BASIC_ENABLED=false`). + No login form, no sign-up. +- EFS volume is encrypted at rest with `RETAIN` removal policy. +- Docker image is multi-stage; final image is based on + `grafana/grafana:latest` (Alpine). +- SQLite datasource is mounted read-only in Grafana + (`mode: ro` in `automatic.yaml`). + +> TODO: No dependency scanning (e.g., `cargo audit`, Dependabot) +> is configured. + +## Agent Guardrails + +- Do NOT push to `strands-agents/devtools` directly; use forks. +- Never commit `metrics.db` manually; the CI workflow handles it. +- Never commit `.env` files or tokens. +- Dashboard JSON files under `provisioning/dashboards/` are + auto-loaded by Grafana. Validate JSON before committing. +- Do not modify `provisioning/datasources/automatic.yaml` unless + the database path or plugin changes. +- The CDK stack uses `RemovalPolicy.RETAIN` on EFS. Do not change + this to `DESTROY` without explicit approval. +- Avoid modifying `docker/entrypoint.sh` seed logic without + testing locally first — a broken entrypoint blocks the entire + dashboard. + +## Extensibility Hooks + +- Add new dashboards by placing JSON files in the appropriate + `provisioning/dashboards/{general,sdks,operations}/` folder. + Grafana picks them up automatically (60s poll). +- Add new CLI subcommands in `strands-metrics/src/main.rs` + (clap derive). +- Track new packages by adding entries to `packages.yaml`. +- Add new goal metrics by adding entries to `goals.yaml` and + running `load-goals`. +- Add team members via `team.yaml` and running `load-team`. +- Environment variables: + - `GITHUB_TOKEN` — required for sync/sweep commands. + - `RECOMPUTE_METRICS=true` — triggers full daily_metrics + recomputation on container startup. + - `GF_*` — standard Grafana env var overrides. + +## Further Reading + +- [README.md](README.md) — Full quick-start, CLI reference, + configuration docs, and deployment guide. +- [goals.yaml](goals.yaml) — Goal threshold configuration + reference with inline documentation. +- [cdk/](cdk/) — CDK stack source and `.env.example`. +- [docker/](docker/) — Dockerfile, Compose, entrypoint, and + sync scripts. +- [provisioning/](provisioning/) — Grafana datasource and + dashboard provisioning configs. From 785585b7dfa3e5c549c6323d012f88c324b603ec Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Thu, 26 Feb 2026 21:46:08 -0500 Subject: [PATCH 13/22] fix: simplify volume section --- .../dashboards/general/health.json | 8332 +++++------------ 1 file changed, 2536 insertions(+), 5796 deletions(-) diff --git a/community-dashboard/provisioning/dashboards/general/health.json b/community-dashboard/provisioning/dashboards/general/health.json index e0ec7ae..a3aa8a9 100644 --- a/community-dashboard/provisioning/dashboards/general/health.json +++ b/community-dashboard/provisioning/dashboards/general/health.json @@ -550,7 +550,7 @@ "h": 1, "w": 24, "x": 0, - "y": 44 + "y": 42 }, "id": 101, "panels": [], @@ -563,7 +563,7 @@ "h": 1, "w": 24, "x": 0, - "y": 61 + "y": 59 }, "id": 102, "panels": [], @@ -576,7 +576,7 @@ "h": 1, "w": 24, "x": 0, - "y": 78 + "y": 76 }, "id": 103, "panels": [], @@ -588,7 +588,7 @@ "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "Current count of open pull requests across selected repositories. Point-in-time snapshot.", + "description": "Current cumulative count of GitHub stars. Point-in-time snapshot.", "fieldConfig": { "defaults": { "color": { @@ -641,8 +641,7 @@ "value": 80 } ] - }, - "unit": "short" + } }, "overrides": [ { @@ -1475,10 +1474,10 @@ "gridPos": { "h": 8, "w": 12, - "x": 12, - "y": 36 + "x": 0, + "y": 77 }, - "id": 11, + "id": 12, "options": { "legend": { "calcs": [], @@ -1495,9 +1494,9 @@ "pluginVersion": "12.3.1", "targets": [ { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \nORDER BY date ASC", + "queryText": "SELECT \n CAST(strftime('%s', week_start) as INTEGER) as time,\n repo as metric,\n stars as value\nFROM (\n SELECT \n date(date, 'weekday 0', '-6 days') as week_start,\n repo,\n stars,\n ROW_NUMBER() OVER (PARTITION BY repo, date(date, 'weekday 0', '-6 days') ORDER BY date DESC) as rn\n FROM daily_metrics \nWHERE repo IN (${repo:singlequote})\n) WHERE rn = 1\nORDER BY week_start ASC", "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n open_issues_count as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "rawQueryText": "SELECT \n CAST(strftime('%s', week_start) as INTEGER) as time,\n repo as metric,\n stars as value\nFROM (\n SELECT \n date(date, 'weekday 0', '-6 days') as week_start,\n repo,\n stars,\n ROW_NUMBER() OVER (PARTITION BY repo, date(date, 'weekday 0', '-6 days') ORDER BY date DESC) as rn\n FROM daily_metrics \nWHERE repo IN (${repo:singlequote})\n) WHERE rn = 1\nORDER BY week_start ASC", "refId": "A", "timeColumns": [ "time", @@ -1505,7 +1504,7 @@ ] } ], - "title": "Total Open PRs (Current)", + "title": "Total Stars (Current)", "transformations": [ { "id": "prepareTimeSeries", @@ -1521,7 +1520,7 @@ "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "Current cumulative count of GitHub stars. Point-in-time snapshot.", + "description": "\u23f1\ufe0f Follows date range. Count of unique community contributors who created PRs in the rolling 7-day window ending on each date.", "fieldConfig": { "defaults": { "color": { @@ -2407,10 +2406,10 @@ "gridPos": { "h": 8, "w": 12, - "x": 0, - "y": 79 + "x": 12, + "y": 77 }, - "id": 12, + "id": 10, "options": { "legend": { "calcs": [], @@ -2427,9 +2426,9 @@ "pluginVersion": "12.3.1", "targets": [ { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "queryText": "SELECT \n CAST(strftime('%s', week_start) as INTEGER) as time,\n repo as metric,\n weekly_community_contributors as value\nFROM (\n SELECT \n date(date, 'weekday 0', '-6 days') as week_start,\n repo,\n weekly_community_contributors,\n ROW_NUMBER() OVER (PARTITION BY repo, date(date, 'weekday 0', '-6 days') ORDER BY date DESC) as rn\n FROM daily_metrics\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n) WHERE rn = 1\nORDER BY week_start ASC", "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n stars as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \nORDER BY date ASC", + "rawQueryText": "SELECT \n CAST(strftime('%s', week_start) as INTEGER) as time,\n repo as metric,\n weekly_community_contributors as value\nFROM (\n SELECT \n date(date, 'weekday 0', '-6 days') as week_start,\n repo,\n weekly_community_contributors,\n ROW_NUMBER() OVER (PARTITION BY repo, date(date, 'weekday 0', '-6 days') ORDER BY date DESC) as rn\n FROM daily_metrics\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n) WHERE rn = 1\nORDER BY week_start ASC", "refId": "A", "timeColumns": [ "time", @@ -2437,7 +2436,7 @@ ] } ], - "title": "Total Stars (Current)", + "title": "Weekly Active Community Contributors", "transformations": [ { "id": "prepareTimeSeries", @@ -2453,7 +2452,7 @@ "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "⏱️ Follows date range. Count of unique community contributors who created PRs in the rolling 7-day window ending on each date.", + "description": "\u23f1\ufe0f Follows date range. 30-day rolling average percentage of merged PRs from community contributors.", "fieldConfig": { "defaults": { "color": { @@ -2483,30 +2482,28 @@ "type": "linear" }, "showPoints": "auto", - "showValues": false, "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { - "mode": "off" + "mode": "dashed" } }, "mappings": [], + "max": 100, + "min": 0, "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": 0 - }, - { - "color": "red", - "value": 80 } ] - } + }, + "unit": "percent" }, "overrides": [ { @@ -2527,13 +2524,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (Internal)" + "options": "value sdk-typescript" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "green", "mode": "fixed" } } @@ -2542,13 +2539,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (External)" + "options": "value tools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "yellow", "mode": "fixed" } } @@ -2557,13 +2554,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (First Response)" + "options": "value docs" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "orange", "mode": "fixed" } } @@ -2572,13 +2569,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (Resolution Time)" + "options": "value agent-builder" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "red", "mode": "fixed" } } @@ -2587,13 +2584,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript" + "options": "value agent-sop" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -2602,13 +2599,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (Internal)" + "options": "value samples" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "purple", "mode": "fixed" } } @@ -2617,13 +2614,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (External)" + "options": "value mcp-server" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -2632,13 +2629,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (First Response)" + "options": "value evals" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -2647,13 +2644,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (Resolution Time)" + "options": "value .github" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "#808080", "mode": "fixed" } } @@ -2662,28 +2659,149 @@ { "matcher": { "id": "byName", - "options": "value tools" + "options": "value devtools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "light-green", "mode": "fixed" } } ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 85 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(date(merged_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(date(merged_at), 'weekday 0', '-6 days') ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date(merged_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(date(merged_at), 'weekday 0', '-6 days') ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'community_pr_percent_min'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Community PR Share (Monthly Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + }, + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. Daily count of PRs closed without being merged.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ { "matcher": { "id": "byName", - "options": "value tools (Internal)" + "options": "value sdk-python" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "blue", "mode": "fixed" } } @@ -2692,13 +2810,13 @@ { "matcher": { "id": "byName", - "options": "value tools (External)" + "options": "value sdk-python (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "blue", "mode": "fixed" } } @@ -2707,13 +2825,13 @@ { "matcher": { "id": "byName", - "options": "value tools (First Response)" + "options": "value sdk-python (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "blue", "mode": "fixed" } } @@ -2722,13 +2840,13 @@ { "matcher": { "id": "byName", - "options": "value tools (Resolution Time)" + "options": "value sdk-python (First Response)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "blue", "mode": "fixed" } } @@ -2737,13 +2855,13 @@ { "matcher": { "id": "byName", - "options": "value docs" + "options": "value sdk-python (Resolution Time)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "blue", "mode": "fixed" } } @@ -2752,13 +2870,13 @@ { "matcher": { "id": "byName", - "options": "value docs (Internal)" + "options": "value sdk-typescript" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "green", "mode": "fixed" } } @@ -2767,13 +2885,13 @@ { "matcher": { "id": "byName", - "options": "value docs (External)" + "options": "value sdk-typescript (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "green", "mode": "fixed" } } @@ -2782,13 +2900,13 @@ { "matcher": { "id": "byName", - "options": "value docs (First Response)" + "options": "value sdk-typescript (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "green", "mode": "fixed" } } @@ -2797,13 +2915,13 @@ { "matcher": { "id": "byName", - "options": "value docs (Resolution Time)" + "options": "value sdk-typescript (First Response)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "green", "mode": "fixed" } } @@ -2812,13 +2930,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder" + "options": "value sdk-typescript (Resolution Time)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "green", "mode": "fixed" } } @@ -2827,13 +2945,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder (Internal)" + "options": "value tools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "yellow", "mode": "fixed" } } @@ -2842,13 +2960,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder (External)" + "options": "value tools (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "yellow", "mode": "fixed" } } @@ -2857,13 +2975,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder (First Response)" + "options": "value tools (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "yellow", "mode": "fixed" } } @@ -2872,13 +2990,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder (Resolution Time)" + "options": "value tools (First Response)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "yellow", "mode": "fixed" } } @@ -2887,13 +3005,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop" + "options": "value tools (Resolution Time)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "yellow", "mode": "fixed" } } @@ -2902,13 +3020,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop (Internal)" + "options": "value docs" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "orange", "mode": "fixed" } } @@ -2917,13 +3035,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop (External)" + "options": "value docs (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "orange", "mode": "fixed" } } @@ -2932,13 +3050,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop (First Response)" + "options": "value docs (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "orange", "mode": "fixed" } } @@ -2947,7 +3065,172 @@ { "matcher": { "id": "byName", - "options": "value agent-sop (Resolution Time)" + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" }, "properties": [ { @@ -3340,28 +3623,37 @@ "h": 8, "w": 12, "x": 12, - "y": 79 + "y": 85 }, - "id": 10, + "id": 9, "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", "tooltip": { "hideZeros": false, "mode": "single", "sort": "none" - } + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 }, "pluginVersion": "12.3.1", "targets": [ { - "queryText": "SELECT\n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n weekly_community_contributors as value\nFROM daily_metrics\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(closed_at), 'weekday 0', '-6 days'), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(closed_at), 'weekday 0', '-6 days'), repo\n\nORDER BY time ASC", "queryType": "table", - "rawQueryText": "SELECT\n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n weekly_community_contributors as value\nFROM daily_metrics\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "rawQueryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(closed_at), 'weekday 0', '-6 days'), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(closed_at), 'weekday 0', '-6 days'), repo\n\nORDER BY time ASC", "refId": "A", "timeColumns": [ "time", @@ -3369,7 +3661,7 @@ ] } ], - "title": "Weekly Active Community Contributors", + "title": "Rejected PRs (Weekly)", "transformations": [ { "id": "prepareTimeSeries", @@ -3378,14 +3670,14 @@ } } ], - "type": "timeseries" + "type": "barchart" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "⏱️ Follows date range. 30-day rolling average percentage of merged PRs from community contributors.", + "description": "\u23f1\ufe0f Follows date range. Daily count of PRs that waited >48 hours for first review.", "fieldConfig": { "defaults": { "color": { @@ -3397,46 +3689,35 @@ "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, + "fillOpacity": 80, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, - "insertNulls": false, - "lineInterpolation": "linear", "lineWidth": 1, - "pointSize": 5, "scaleDistribution": { "type": "linear" }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], - "max": 100, - "min": 0, "thresholds": { "mode": "absolute", "steps": [ { "color": "green", - "value": 0 + "value": null + }, + { + "color": "red", + "value": 80 } ] - }, - "unit": "percent" + } }, "overrides": [ { @@ -3603,84 +3884,52 @@ } } ] - }, - { - "matcher": { - "id": "byName", - "options": "Goal (20%)" - }, - "properties": [ - { - "id": "custom.lineStyle", - "value": { - "dash": [ - 10, - 10 - ], - "fill": "dash" - } - }, - { - "id": "custom.lineWidth", - "value": 2 - }, - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - }, - { - "id": "custom.fillOpacity", - "value": 0 - } - ] } ] }, "gridPos": { "h": 8, "w": 12, - "x": 0, - "y": 87 + "x": 12, + "y": 51 }, - "id": 18, + "id": 19, "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, + "orientation": "auto", + "showValue": "never", + "stacking": "normal", "tooltip": { + "hideZeros": false, "mode": "single", "sort": "none" - } + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 }, "targets": [ { - "queryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "queryText": "SELECT \n CAST(strftime('%s', date(date(first_review_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(first_review_at), 'weekday 0', '-6 days'), repo\nORDER BY first_review_at ASC", "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo as metric,\n AVG(\n CASE WHEN json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR') \n THEN 100.0 ELSE 0.0 END\n ) OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\nORDER BY merged_at ASC", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date(first_review_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(first_review_at), 'weekday 0', '-6 days'), repo\nORDER BY first_review_at ASC", "refId": "A", "timeColumns": [ "time", "ts" ] - }, - { - "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'", - "queryType": "table", - "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'community_pr_percent_min'", - "refId": "Goal", - "timeColumns": [ - "time" - ] - } - ], - "title": "Community PR Share (30-Day Rolling)", - "transformations": [ + } + ], + "title": "Slow Reviews (>48h Wait)", + "transformations": [ { "id": "prepareTimeSeries", "options": { @@ -3688,14 +3937,14 @@ } } ], - "type": "timeseries" + "type": "barchart" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "⏱️ Follows date range. Daily count of PRs closed without being merged.", + "description": "\u23f1\ufe0f Follows date range. 7-day rolling average of CI failure rate.", "fieldConfig": { "defaults": { "color": { @@ -3707,19 +3956,31 @@ "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", - "fillOpacity": 80, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", "lineWidth": 1, + "pointSize": 5, "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, "thresholdsStyle": { - "mode": "off" + "mode": "dashed" } }, "mappings": [], @@ -3730,12 +3991,17 @@ "color": "green", "value": null }, + { + "color": "yellow", + "value": 22.5 + }, { "color": "red", - "value": 80 + "value": 30.0 } ] - } + }, + "unit": "percent" }, "overrides": [ { @@ -3756,13 +4022,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (Internal)" + "options": "value sdk-typescript" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "green", "mode": "fixed" } } @@ -3771,13 +4037,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (External)" + "options": "value tools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "yellow", "mode": "fixed" } } @@ -3786,13 +4052,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (First Response)" + "options": "value docs" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "orange", "mode": "fixed" } } @@ -3801,13 +4067,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (Resolution Time)" + "options": "value agent-builder" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "red", "mode": "fixed" } } @@ -3816,13 +4082,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript" + "options": "value agent-sop" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -3831,13 +4097,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (Internal)" + "options": "value samples" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "purple", "mode": "fixed" } } @@ -3846,13 +4112,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (External)" + "options": "value mcp-server" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -3861,13 +4127,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (First Response)" + "options": "value evals" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -3876,13 +4142,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (Resolution Time)" + "options": "value .github" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "#808080", "mode": "fixed" } } @@ -3891,58 +4157,158 @@ { "matcher": { "id": "byName", - "options": "value tools" + "options": "value devtools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "light-green", "mode": "fixed" } } ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 60 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n ROUND(CAST(SUM(ci_failures) AS FLOAT) / NULLIF(SUM(ci_runs), 0) * 100, 2) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n ROUND(CAST(SUM(ci_failures) AS FLOAT) / NULLIF(SUM(ci_runs), 0) * 100, 2) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'ci_failure_rate_percent'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'ci_failure_rate_percent'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "CI Failure Rate (Weekly)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + }, + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" } ] + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. 7-day rolling average of lines changed per day. Days >10k lines filtered out.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "properties": [ + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } + "color": "green", + "value": 0 } ] }, + "unit": "short" + }, + "overrides": [ { "matcher": { "id": "byName", - "options": "value tools (First Response)" + "options": "value sdk-python" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "blue", "mode": "fixed" } } @@ -3951,13 +4317,13 @@ { "matcher": { "id": "byName", - "options": "value tools (Resolution Time)" + "options": "value sdk-typescript" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "green", "mode": "fixed" } } @@ -3966,13 +4332,13 @@ { "matcher": { "id": "byName", - "options": "value docs" + "options": "value tools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "yellow", "mode": "fixed" } } @@ -3981,7 +4347,7 @@ { "matcher": { "id": "byName", - "options": "value docs (Internal)" + "options": "value docs" }, "properties": [ { @@ -3996,13 +4362,13 @@ { "matcher": { "id": "byName", - "options": "value docs (External)" + "options": "value agent-builder" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "red", "mode": "fixed" } } @@ -4011,13 +4377,13 @@ { "matcher": { "id": "byName", - "options": "value docs (First Response)" + "options": "value agent-sop" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -4026,13 +4392,13 @@ { "matcher": { "id": "byName", - "options": "value docs (Resolution Time)" + "options": "value samples" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "purple", "mode": "fixed" } } @@ -4041,13 +4407,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder" + "options": "value mcp-server" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -4056,13 +4422,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder (Internal)" + "options": "value evals" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -4071,13 +4437,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder (External)" + "options": "value .github" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "#808080", "mode": "fixed" } } @@ -4086,148 +4452,139 @@ { "matcher": { "id": "byName", - "options": "value agent-builder (First Response)" + "options": "value devtools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", + "fixedColor": "light-green", "mode": "fixed" } } ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 68 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(churn_additions + churn_deletions) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(churn_additions + churn_deletions) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Code Churn (Weekly)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. 30-day rolling average of (PRs merged / PRs opened) \u00d7 100%.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] + "thresholdsStyle": { + "mode": "dashed" + } }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ + "color": "red", + "value": null + }, { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ + "color": "yellow", + "value": 42.0 + }, { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } + "color": "green", + "value": 60.0 } ] }, + "unit": "percent" + }, + "overrides": [ { "matcher": { "id": "byName", - "options": "value samples (External)" + "options": "value sdk-python" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "blue", "mode": "fixed" } } @@ -4236,13 +4593,13 @@ { "matcher": { "id": "byName", - "options": "value samples (First Response)" + "options": "value sdk-typescript" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "green", "mode": "fixed" } } @@ -4251,13 +4608,13 @@ { "matcher": { "id": "byName", - "options": "value samples (Resolution Time)" + "options": "value tools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "yellow", "mode": "fixed" } } @@ -4266,13 +4623,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server" + "options": "value docs" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "orange", "mode": "fixed" } } @@ -4281,13 +4638,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server (Internal)" + "options": "value agent-builder" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "red", "mode": "fixed" } } @@ -4296,13 +4653,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server (External)" + "options": "value agent-sop" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -4311,13 +4668,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server (First Response)" + "options": "value samples" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "purple", "mode": "fixed" } } @@ -4326,7 +4683,7 @@ { "matcher": { "id": "byName", - "options": "value mcp-server (Resolution Time)" + "options": "value mcp-server" }, "properties": [ { @@ -4356,28 +4713,13 @@ { "matcher": { "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" + "options": "value .github" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-green", + "fixedColor": "#808080", "mode": "fixed" } } @@ -4386,28 +4728,158 @@ { "matcher": { "id": "byName", - "options": "value evals (First Response)" + "options": "value devtools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-green", + "fixedColor": "light-green", "mode": "fixed" } } ] - }, + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 60 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(date(COALESCE(merged_at, closed_at)), 'weekday 0', '-6 days') as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(date(COALESCE(merged_at, closed_at)), 'weekday 0', '-6 days'), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(date(COALESCE(merged_at, closed_at)), 'weekday 0', '-6 days') as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN (${repo:singlequote})\n GROUP BY date(date(COALESCE(merged_at, closed_at)), 'weekday 0', '-6 days'), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'pr_acceptance_rate_min'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'pr_acceptance_rate_min'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PR Acceptance Rate (Monthly Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + }, + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. Week-over-week change in open PR count.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": true, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "short" + }, + "overrides": [ { "matcher": { "id": "byName", - "options": "value evals (Resolution Time)" + "options": "value sdk-python" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-green", + "fixedColor": "blue", "mode": "fixed" } } @@ -4416,13 +4888,13 @@ { "matcher": { "id": "byName", - "options": "value .github" + "options": "value sdk-typescript" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "green", "mode": "fixed" } } @@ -4431,13 +4903,13 @@ { "matcher": { "id": "byName", - "options": "value .github (Internal)" + "options": "value tools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "yellow", "mode": "fixed" } } @@ -4446,13 +4918,13 @@ { "matcher": { "id": "byName", - "options": "value .github (External)" + "options": "value docs" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "orange", "mode": "fixed" } } @@ -4461,13 +4933,13 @@ { "matcher": { "id": "byName", - "options": "value .github (First Response)" + "options": "value agent-builder" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "red", "mode": "fixed" } } @@ -4476,13 +4948,13 @@ { "matcher": { "id": "byName", - "options": "value .github (Resolution Time)" + "options": "value agent-sop" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -4491,13 +4963,13 @@ { "matcher": { "id": "byName", - "options": "value devtools" + "options": "value samples" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "purple", "mode": "fixed" } } @@ -4506,13 +4978,13 @@ { "matcher": { "id": "byName", - "options": "value devtools (Internal)" + "options": "value mcp-server" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -4521,13 +4993,13 @@ { "matcher": { "id": "byName", - "options": "value devtools (External)" + "options": "value evals" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -4536,13 +5008,13 @@ { "matcher": { "id": "byName", - "options": "value devtools (First Response)" + "options": "value .github" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "#808080", "mode": "fixed" } } @@ -4551,7 +5023,7 @@ { "matcher": { "id": "byName", - "options": "value devtools (Resolution Time)" + "options": "value devtools" }, "properties": [ { @@ -4569,37 +5041,26 @@ "h": 8, "w": 12, "x": 12, - "y": 87 + "y": 68 }, - "id": 9, + "id": 16, "options": { - "barRadius": 0, - "barWidth": 0.97, - "fullHighlight": false, - "groupWidth": 0.7, "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, - "orientation": "auto", - "showValue": "never", - "stacking": "normal", "tooltip": { - "hideZeros": false, "mode": "single", "sort": "none" - }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 100 + } }, - "pluginVersion": "12.3.1", "targets": [ { - "queryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "queryText": "SELECT \n CAST(strftime('%s', week_start) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 1) OVER (PARTITION BY repo ORDER BY week_start) as value\nFROM (\n SELECT \n date(date, 'weekday 0', '-6 days') as week_start,\n repo,\n open_issues_count,\n ROW_NUMBER() OVER (PARTITION BY repo, date(date, 'weekday 0', '-6 days') ORDER BY date DESC) as rn\n FROM daily_metrics\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n) WHERE rn = 1\nORDER BY week_start ASC", "queryType": "table", - "rawQueryText": "-- Internal Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nUNION ALL\n\n-- External Rejection\nSELECT \n CAST(strftime('%s', date(closed_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(closed_at), repo\n\nORDER BY time ASC", + "rawQueryText": "SELECT \n CAST(strftime('%s', week_start) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 1) OVER (PARTITION BY repo ORDER BY week_start) as value\nFROM (\n SELECT \n date(date, 'weekday 0', '-6 days') as week_start,\n repo,\n open_issues_count,\n ROW_NUMBER() OVER (PARTITION BY repo, date(date, 'weekday 0', '-6 days') ORDER BY date DESC) as rn\n FROM daily_metrics\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n) WHERE rn = 1\nORDER BY week_start ASC", "refId": "A", "timeColumns": [ "time", @@ -4607,7 +5068,7 @@ ] } ], - "title": "Rejected PRs (Daily)", + "title": "Backlog Growth (WoW)", "transformations": [ { "id": "prepareTimeSeries", @@ -4616,14 +5077,14 @@ } } ], - "type": "barchart" + "type": "timeseries" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "⏱️ Follows date range. Daily count of PRs that waited >48 hours for first review.", + "description": "\u23f1\ufe0f Follows date range. Average hours until first response on issues/PRs.", "fieldConfig": { "defaults": { "color": { @@ -4635,19 +5096,32 @@ "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", - "fillOpacity": 80, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", "lineWidth": 1, + "pointSize": 5, "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, "thresholdsStyle": { - "mode": "off" + "mode": "dashed" } }, "mappings": [], @@ -4658,12 +5132,17 @@ "color": "green", "value": null }, + { + "color": "yellow", + "value": 18.0 + }, { "color": "red", - "value": 80 + "value": 24.0 } ] - } + }, + "unit": "h" }, "overrides": [ { @@ -4684,13 +5163,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript" + "options": "value sdk-python (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "blue", "mode": "fixed" } } @@ -4699,13 +5178,13 @@ { "matcher": { "id": "byName", - "options": "value tools" + "options": "value sdk-python (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "blue", "mode": "fixed" } } @@ -4714,13 +5193,13 @@ { "matcher": { "id": "byName", - "options": "value docs" + "options": "value sdk-python (First Response)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "blue", "mode": "fixed" } } @@ -4729,13 +5208,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder" + "options": "value sdk-python (Resolution Time)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "blue", "mode": "fixed" } } @@ -4744,13 +5223,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop" + "options": "value sdk-typescript" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "green", "mode": "fixed" } } @@ -4759,13 +5238,13 @@ { "matcher": { "id": "byName", - "options": "value samples" + "options": "value sdk-typescript (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "green", "mode": "fixed" } } @@ -4774,13 +5253,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server" + "options": "value sdk-typescript (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "green", "mode": "fixed" } } @@ -4789,13 +5268,13 @@ { "matcher": { "id": "byName", - "options": "value evals" + "options": "value sdk-typescript (First Response)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-green", + "fixedColor": "green", "mode": "fixed" } } @@ -4804,13 +5283,13 @@ { "matcher": { "id": "byName", - "options": "value .github" + "options": "value sdk-typescript (Resolution Time)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "green", "mode": "fixed" } } @@ -4819,147 +5298,103 @@ { "matcher": { "id": "byName", - "options": "value devtools" + "options": "value tools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "yellow", "mode": "fixed" } } ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 53 - }, - "id": 19, - "options": { - "barRadius": 0, - "barWidth": 0.97, - "fullHighlight": false, - "groupWidth": 0.7, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "orientation": "auto", - "showValue": "never", - "stacking": "normal", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 100 - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date(first_review_at)) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(first_review_at), repo\nORDER BY first_review_at ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date(first_review_at)) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(reviews.submitted_at) as first_review_at\n FROM pull_requests pr\n INNER JOIN pr_reviews reviews \n ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n GROUP BY pr.repo, pr.number\n HAVING (julianday(MIN(reviews.submitted_at)) - julianday(pr.created_at)) * 24 > 48\n) bottlenecks\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_review_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(first_review_at), repo\nORDER BY first_review_at ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Slow Reviews (>48h Wait)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "barchart" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "⏱️ Follows date range. 7-day rolling average of CI failure rate.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" }, - "thresholdsStyle": { - "mode": "off" - } + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ { - "color": "green", - "value": null - }, + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ { - "color": "yellow", - "value": 22.5 - }, + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ { - "color": "red", - "value": 30.0 + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } } ] }, - "unit": "percent" - }, - "overrides": [ { "matcher": { "id": "byName", - "options": "value sdk-python" + "options": "value docs (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "orange", "mode": "fixed" } } @@ -4968,13 +5403,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript" + "options": "value docs (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "orange", "mode": "fixed" } } @@ -4983,13 +5418,13 @@ { "matcher": { "id": "byName", - "options": "value tools" + "options": "value docs (First Response)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "orange", "mode": "fixed" } } @@ -4998,7 +5433,7 @@ { "matcher": { "id": "byName", - "options": "value docs" + "options": "value docs (Resolution Time)" }, "properties": [ { @@ -5028,13 +5463,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop" + "options": "value agent-builder (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "red", "mode": "fixed" } } @@ -5043,13 +5478,13 @@ { "matcher": { "id": "byName", - "options": "value samples" + "options": "value agent-builder (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "red", "mode": "fixed" } } @@ -5058,13 +5493,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server" + "options": "value agent-builder (First Response)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "red", "mode": "fixed" } } @@ -5073,13 +5508,13 @@ { "matcher": { "id": "byName", - "options": "value evals" + "options": "value agent-builder (Resolution Time)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-green", + "fixedColor": "red", "mode": "fixed" } } @@ -5088,13 +5523,13 @@ { "matcher": { "id": "byName", - "options": "value .github" + "options": "value agent-sop" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -5103,13 +5538,13 @@ { "matcher": { "id": "byName", - "options": "value devtools" + "options": "value agent-sop (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -5118,156 +5553,88 @@ { "matcher": { "id": "byName", - "options": "Goal (30%)" + "options": "value agent-sop (External)" }, "properties": [ { - "id": "custom.lineStyle", + "id": "color", "value": { - "dash": [ - 10, - 10 - ], - "fill": "dash" + "fixedColor": "dark-red", + "mode": "fixed" } - }, + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ { - "id": "custom.lineWidth", - "value": 2 - }, + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "dark-red", "mode": "fixed" } - }, + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ { - "id": "custom.fillOpacity", - "value": 0 + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } } ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 62 - }, - "id": 13, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(ROUND(CAST(ci_failures AS FLOAT) / NULLIF(ci_runs, 0) * 100, 2)) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE ci_runs > 0\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - }, - { - "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'", - "queryType": "table", - "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'ci_failure_rate_percent'", - "refId": "Goal", - "timeColumns": [ - "time" - ] - } - ], - "title": "CI Failure Rate (7-Day Rolling)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "⏱️ Follows date range. 7-day rolling average of lines changed per day. Days >10k lines filtered out.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ + "properties": [ { - "color": "green", - "value": 0 + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } } ] }, - "unit": "short" - }, - "overrides": [ { "matcher": { "id": "byName", - "options": "value sdk-python" + "options": "value samples (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "purple", "mode": "fixed" } } @@ -5276,13 +5643,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript" + "options": "value samples (First Response)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "purple", "mode": "fixed" } } @@ -5291,13 +5658,13 @@ { "matcher": { "id": "byName", - "options": "value tools" + "options": "value samples (Resolution Time)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "purple", "mode": "fixed" } } @@ -5306,13 +5673,13 @@ { "matcher": { "id": "byName", - "options": "value docs" + "options": "value mcp-server" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -5321,13 +5688,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder" + "options": "value mcp-server (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -5336,13 +5703,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop" + "options": "value mcp-server (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -5351,13 +5718,13 @@ { "matcher": { "id": "byName", - "options": "value samples" + "options": "value mcp-server (First Response)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -5366,7 +5733,7 @@ { "matcher": { "id": "byName", - "options": "value mcp-server" + "options": "value mcp-server (Resolution Time)" }, "properties": [ { @@ -5396,13 +5763,13 @@ { "matcher": { "id": "byName", - "options": "value .github" + "options": "value evals (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -5411,139 +5778,28 @@ { "matcher": { "id": "byName", - "options": "value devtools" + "options": "value evals (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "dark-green", "mode": "fixed" } } ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 70 - }, - "id": 14, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(churn_additions + churn_deletions) \n OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as value\nFROM daily_metrics\nWHERE (churn_additions > 0 OR churn_deletions > 0)\n AND (churn_additions + churn_deletions) <= 10000\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Code Churn (7-Day Rolling)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "⏱️ Follows date range. 30-day rolling average of (PRs merged / PRs opened) × 100%.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "max": 100, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "yellow", - "value": 42.0 - }, - { - "color": "green", - "value": 60.0 - } - ] }, - "unit": "percent" - }, - "overrides": [ { "matcher": { "id": "byName", - "options": "value sdk-python" + "options": "value evals (First Response)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -5552,13 +5808,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript" + "options": "value evals (Resolution Time)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -5567,13 +5823,13 @@ { "matcher": { "id": "byName", - "options": "value tools" + "options": "value .github" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "#808080", "mode": "fixed" } } @@ -5582,13 +5838,13 @@ { "matcher": { "id": "byName", - "options": "value docs" + "options": "value .github (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "#808080", "mode": "fixed" } } @@ -5597,13 +5853,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder" + "options": "value .github (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "#808080", "mode": "fixed" } } @@ -5612,13 +5868,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop" + "options": "value .github (First Response)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "#808080", "mode": "fixed" } } @@ -5627,13 +5883,13 @@ { "matcher": { "id": "byName", - "options": "value samples" + "options": "value .github (Resolution Time)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "#808080", "mode": "fixed" } } @@ -5642,13 +5898,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server" + "options": "value devtools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "light-green", "mode": "fixed" } } @@ -5657,13 +5913,13 @@ { "matcher": { "id": "byName", - "options": "value evals" + "options": "value devtools (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-green", + "fixedColor": "light-green", "mode": "fixed" } } @@ -5672,13 +5928,13 @@ { "matcher": { "id": "byName", - "options": "value .github" + "options": "value devtools (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "light-green", "mode": "fixed" } } @@ -5687,7 +5943,7 @@ { "matcher": { "id": "byName", - "options": "value devtools" + "options": "value devtools (First Response)" }, "properties": [ { @@ -5702,33 +5958,15 @@ { "matcher": { "id": "byName", - "options": "Goal (60%)" + "options": "value devtools (Resolution Time)" }, "properties": [ - { - "id": "custom.lineStyle", - "value": { - "dash": [ - 10, - 10 - ], - "fill": "dash" - } - }, - { - "id": "custom.lineWidth", - "value": 2 - }, { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "light-green", "mode": "fixed" } - }, - { - "id": "custom.fillOpacity", - "value": 0 } ] } @@ -5737,10 +5975,10 @@ "gridPos": { "h": 8, "w": 12, - "x": 12, - "y": 62 + "x": 0, + "y": 51 }, - "id": 15, + "id": 7, "options": { "legend": { "calcs": [], @@ -5749,15 +5987,17 @@ "showLegend": true }, "tooltip": { + "hideZeros": false, "mode": "single", "sort": "none" } }, + "pluginVersion": "12.3.1", "targets": [ { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "queryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND avg_issue_resolution_time > 0\nORDER BY time ASC", "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n AVG(\n CAST(merged_count AS FLOAT) / NULLIF(total_count, 0) * 100\n ) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n date(COALESCE(merged_at, closed_at)) as date,\n repo,\n SUM(CASE WHEN merged_at IS NOT NULL THEN 1 ELSE 0 END) as merged_count,\n COUNT(*) as total_count\n FROM pull_requests\n WHERE (merged_at IS NOT NULL OR (state = 'closed' AND merged_at IS NULL))\n AND repo IN (${repo:singlequote})\n GROUP BY date(COALESCE(merged_at, closed_at)), repo\n) subquery\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", + "rawQueryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND avg_issue_resolution_time > 0\nORDER BY time ASC", "refId": "A", "timeColumns": [ "time", @@ -5765,22 +6005,42 @@ ] }, { - "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'", + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'time_to_first_response_hours'", "queryType": "table", - "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'pr_acceptance_rate_min'", - "refId": "Goal", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'time_to_first_response_hours'", + "refId": "Thresholds", "timeColumns": [ - "time" + "time", + "ts" ] } ], - "title": "PR Acceptance Rate (30-Day Rolling)", + "title": "Time to First Response", "transformations": [ { "id": "prepareTimeSeries", "options": { "format": "multi" } + }, + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } } ], "type": "timeseries" @@ -5790,7 +6050,7 @@ "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "⏱️ Follows date range. Week-over-week change in open PR count.", + "description": "\u23f1\ufe0f Follows date range. 14-day rolling average hours from PR open to merge, by contributor type.", "fieldConfig": { "defaults": { "color": { @@ -5798,14 +6058,14 @@ }, "custom": { "axisBorderShow": false, - "axisCenteredZero": true, + "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "barWidthFactor": 0.6, "drawStyle": "line", - "fillOpacity": 10, + "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, @@ -5814,7 +6074,7 @@ }, "insertNulls": false, "lineInterpolation": "linear", - "lineWidth": 2, + "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" @@ -5826,7 +6086,7 @@ "mode": "none" }, "thresholdsStyle": { - "mode": "off" + "mode": "dashed" } }, "mappings": [], @@ -5835,17 +6095,25 @@ "steps": [ { "color": "green", - "value": 0 + "value": null + }, + { + "color": "yellow", + "value": 252.0 + }, + { + "color": "red", + "value": 336.0 } ] }, - "unit": "short" + "unit": "h" }, "overrides": [ { "matcher": { "id": "byName", - "options": "value sdk-python" + "options": "value sdk-python (Internal)" }, "properties": [ { @@ -5860,13 +6128,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript" + "options": "value sdk-python (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "blue", "mode": "fixed" } } @@ -5875,13 +6143,13 @@ { "matcher": { "id": "byName", - "options": "value tools" + "options": "value sdk-typescript (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "green", "mode": "fixed" } } @@ -5890,13 +6158,13 @@ { "matcher": { "id": "byName", - "options": "value docs" + "options": "value sdk-typescript (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "green", "mode": "fixed" } } @@ -5905,13 +6173,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder" + "options": "value tools (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "yellow", "mode": "fixed" } } @@ -5920,13 +6188,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop" + "options": "value tools (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "yellow", "mode": "fixed" } } @@ -5935,13 +6203,13 @@ { "matcher": { "id": "byName", - "options": "value samples" + "options": "value docs (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "orange", "mode": "fixed" } } @@ -5950,13 +6218,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server" + "options": "value docs (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "orange", "mode": "fixed" } } @@ -5965,13 +6233,13 @@ { "matcher": { "id": "byName", - "options": "value evals" + "options": "value agent-builder (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-green", + "fixedColor": "red", "mode": "fixed" } } @@ -5980,13 +6248,13 @@ { "matcher": { "id": "byName", - "options": "value .github" + "options": "value agent-builder (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "red", "mode": "fixed" } } @@ -5995,120 +6263,28 @@ { "matcher": { "id": "byName", - "options": "value devtools" + "options": "value agent-sop (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "dark-red", "mode": "fixed" } } ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 70 - }, - "id": 16, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time,\n repo as metric,\n open_issues_count - LAG(open_issues_count, 7) OVER (PARTITION BY repo ORDER BY date) as value\nFROM daily_metrics\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Backlog Growth (WoW)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "⏱️ Follows date range. Daily count of new GitHub Issues opened.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1, - "scaleDistribution": { - "type": "linear" - }, - "thresholdsStyle": { - "mode": "off" - } }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ { "matcher": { "id": "byName", - "options": "value sdk-python" + "options": "value agent-sop (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -6117,13 +6293,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (Internal)" + "options": "value samples (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "purple", "mode": "fixed" } } @@ -6132,13 +6308,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (External)" + "options": "value samples (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "purple", "mode": "fixed" } } @@ -6147,13 +6323,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (First Response)" + "options": "value mcp-server (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -6162,13 +6338,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (Resolution Time)" + "options": "value mcp-server (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -6177,13 +6353,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript" + "options": "value evals (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -6192,13 +6368,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (Internal)" + "options": "value evals (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -6207,13 +6383,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (External)" + "options": "value .github (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "#808080", "mode": "fixed" } } @@ -6222,13 +6398,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (First Response)" + "options": "value .github (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "#808080", "mode": "fixed" } } @@ -6237,13 +6413,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-typescript (Resolution Time)" + "options": "value devtools (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "green", + "fixedColor": "light-green", "mode": "fixed" } } @@ -6252,58 +6428,166 @@ { "matcher": { "id": "byName", - "options": "value tools" + "options": "value devtools (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "light-green", "mode": "fixed" } } ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 43 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(date(merged_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(date(merged_at), 'weekday 0', '-6 days') ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(date(merged_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(date(merged_at), 'weekday 0', '-6 days') ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(date(merged_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(date(merged_at), 'weekday 0', '-6 days') ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(date(merged_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(date(merged_at), 'weekday 0', '-6 days') ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'cycle_time_hours'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'cycle_time_hours'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Cycle Time (Bi-Weekly Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + }, + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" } ] + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. 14-day rolling average hours until first PR review, by contributor type.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "properties": [ + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 54.0 + }, + { + "color": "red", + "value": 72.0 } ] }, + "unit": "h" + }, + "overrides": [ { "matcher": { "id": "byName", - "options": "value tools (First Response)" + "options": "value sdk-python (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "blue", "mode": "fixed" } } @@ -6312,13 +6596,13 @@ { "matcher": { "id": "byName", - "options": "value tools (Resolution Time)" + "options": "value sdk-python (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "blue", "mode": "fixed" } } @@ -6327,13 +6611,13 @@ { "matcher": { "id": "byName", - "options": "value docs" + "options": "value sdk-typescript (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "green", "mode": "fixed" } } @@ -6342,13 +6626,13 @@ { "matcher": { "id": "byName", - "options": "value docs (Internal)" + "options": "value sdk-typescript (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "green", "mode": "fixed" } } @@ -6357,13 +6641,13 @@ { "matcher": { "id": "byName", - "options": "value docs (External)" + "options": "value tools (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "yellow", "mode": "fixed" } } @@ -6372,13 +6656,13 @@ { "matcher": { "id": "byName", - "options": "value docs (First Response)" + "options": "value tools (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "yellow", "mode": "fixed" } } @@ -6387,7 +6671,7 @@ { "matcher": { "id": "byName", - "options": "value docs (Resolution Time)" + "options": "value docs (Internal)" }, "properties": [ { @@ -6402,13 +6686,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder" + "options": "value docs (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "orange", "mode": "fixed" } } @@ -6447,13 +6731,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder (First Response)" + "options": "value agent-sop (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -6462,13 +6746,13 @@ { "matcher": { "id": "byName", - "options": "value agent-builder (Resolution Time)" + "options": "value agent-sop (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "dark-red", "mode": "fixed" } } @@ -6477,13 +6761,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop" + "options": "value samples (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "purple", "mode": "fixed" } } @@ -6492,13 +6776,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop (Internal)" + "options": "value samples (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "purple", "mode": "fixed" } } @@ -6507,13 +6791,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop (External)" + "options": "value mcp-server (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -6522,13 +6806,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop (First Response)" + "options": "value mcp-server (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "dark-orange", "mode": "fixed" } } @@ -6537,13 +6821,13 @@ { "matcher": { "id": "byName", - "options": "value agent-sop (Resolution Time)" + "options": "value evals (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-red", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -6552,13 +6836,13 @@ { "matcher": { "id": "byName", - "options": "value samples" + "options": "value evals (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "dark-green", "mode": "fixed" } } @@ -6567,13 +6851,13 @@ { "matcher": { "id": "byName", - "options": "value samples (Internal)" + "options": "value .github (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "#808080", "mode": "fixed" } } @@ -6582,13 +6866,13 @@ { "matcher": { "id": "byName", - "options": "value samples (External)" + "options": "value .github (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "#808080", "mode": "fixed" } } @@ -6597,13 +6881,13 @@ { "matcher": { "id": "byName", - "options": "value samples (First Response)" + "options": "value devtools (Internal)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "light-green", "mode": "fixed" } } @@ -6612,4118 +6896,187 @@ { "matcher": { "id": "byName", - "options": "value samples (Resolution Time)" + "options": "value devtools (External)" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "light-green", "mode": "fixed" } } ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 28 - }, - "id": 2, - "options": { - "barRadius": 0, - "barWidth": 0.97, - "fullHighlight": false, - "groupWidth": 0.7, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "orientation": "auto", - "showValue": "never", - "stacking": "normal", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 100 - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_opened as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Issues Opened (Daily)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "barchart" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "⏱️ Follows date range. Daily count of GitHub Issues closed.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1, - "scaleDistribution": { - "type": "linear" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 36 - }, - "id": 3, - "options": { - "barRadius": 0, - "barWidth": 0.97, - "fullHighlight": false, - "groupWidth": 0.7, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "orientation": "auto", - "showValue": "never", - "stacking": "normal", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 100 - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n issues_closed as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Issues Closed (Daily)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "barchart" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "⏱️ Follows date range. Daily count of pull requests merged.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1, - "scaleDistribution": { - "type": "linear" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 28 - }, - "id": 1, - "options": { - "barRadius": 0, - "barWidth": 0.97, - "fullHighlight": false, - "groupWidth": 0.7, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "orientation": "auto", - "showValue": "never", - "stacking": "normal", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 100 - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "queryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo as metric, \n prs_merged as value \nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND prs_merged > 0\n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nORDER BY date ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "PRs Merged (Daily)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "barchart" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "⏱️ Follows date range. Average hours until first response on issues/PRs.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 18.0 - }, - { - "color": "red", - "value": 24.0 - } - ] - }, - "unit": "h" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Goal (24h)" - }, - "properties": [ - { - "id": "custom.lineStyle", - "value": { - "dash": [ - 10, - 10 - ], - "fill": "dash" - } - }, - { - "id": "custom.lineWidth", - "value": 2 - }, - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - }, - { - "id": "custom.fillOpacity", - "value": 0 - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 53 - }, - "id": 7, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.3.1", - "targets": [ - { - "queryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND avg_issue_resolution_time > 0\nORDER BY time ASC", - "queryType": "table", - "rawQueryText": "-- Time to First Response\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (First Response)' as metric, \n AVG(time_to_first_response) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND time_to_first_response > 0\n\nUNION ALL\n\n-- Issue Resolution Time\nSELECT \n CAST(strftime('%s', date) as INTEGER) as time, \n repo || ' (Resolution Time)' as metric, \n AVG(avg_issue_resolution_time) OVER (PARTITION BY repo ORDER BY date ROWS BETWEEN 30 PRECEDING AND CURRENT ROW) as value \nFROM daily_metrics WHERE repo IN (${repo:singlequote}) AND avg_issue_resolution_time > 0\nORDER BY time ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - }, - { - "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'", - "queryType": "table", - "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_response_hours'", - "refId": "Goal", - "timeColumns": [ - "time" - ] - } - ], - "title": "Time to First Response", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "⏱️ Follows date range. 14-day rolling average hours from PR open to merge, by contributor type.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 252.0 - }, - { - "color": "red", - "value": 336.0 - } - ] - }, - "unit": "h" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Goal (14d)" - }, - "properties": [ - { - "id": "custom.lineStyle", - "value": { - "dash": [ - 10, - 10 - ], - "fill": "dash" - } - }, - { - "id": "custom.lineWidth", - "value": 2 - }, - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - }, - { - "id": "custom.fillOpacity", - "value": 0 - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 45 - }, - "id": 17, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", - "queryType": "table", - "rawQueryText": "-- Internal Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Cycle Time\nSELECT \n CAST(strftime('%s', date(merged_at)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(merged_at) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(merged_at) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM pull_requests\nWHERE merged_at IS NOT NULL\n AND json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(merged_at)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - }, - { - "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'", - "queryType": "table", - "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'cycle_time_hours'", - "refId": "Goal", - "timeColumns": [ - "time" - ] - } - ], - "title": "Cycle Time (14-Day Rolling)", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "⏱️ Follows date range. 14-day rolling average hours until first PR review, by contributor type.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 54.0 - }, - { - "color": "red", - "value": 72.0 - } - ] - }, - "unit": "h" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 43 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(date(first_response), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(date(first_response), 'weekday 0', '-6 days') ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(date(first_response), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(date(first_response), 'weekday 0', '-6 days') ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(date(first_response), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(date(first_response), 'weekday 0', '-6 days') ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(date(first_response), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(date(first_response), 'weekday 0', '-6 days') ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'time_to_first_review_hours'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'time_to_first_review_hours'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Time to First Review (Bi-Weekly Rolling)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + }, + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" } ] + } + } + ], + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 93 + }, + "id": 104, + "panels": [], + "title": "Contributor Insights", + "type": "row" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. Daily count of first-time vs returning contributors.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] + "thresholdsStyle": { + "mode": "off" + } }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } + "color": "green", + "value": null } ] - }, + } + }, + "overrides": [ { "matcher": { "id": "byName", - "options": "value devtools (External)" + "options": "New Contributors" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "green", "mode": "fixed" } } ] }, { - "matcher": { - "id": "byName", - "options": "Goal (72h)" - }, - "properties": [ - { - "id": "custom.lineStyle", - "value": { - "dash": [ - 10, - 10 - ], - "fill": "dash" - } - }, - { - "id": "custom.lineWidth", - "value": 2 - }, + "matcher": { + "id": "byName", + "options": "Returning Contributors" + }, + "properties": [ { "id": "color", "value": { - "fixedColor": "red", + "fixedColor": "blue", "mode": "fixed" } - }, - { - "id": "custom.fillOpacity", - "value": 0 } ] } @@ -10732,44 +7085,38 @@ "gridPos": { "h": 8, "w": 12, - "x": 12, - "y": 45 + "x": 0, + "y": 94 }, - "id": 20, + "id": 21, "options": { "legend": { - "calcs": [], + "calcs": [ + "sum" + ], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { - "mode": "single", + "hideZeros": false, + "mode": "multi", "sort": "none" } }, "targets": [ { - "queryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(date(created_at), 'weekday 0', '-6 days'), author\n)\nSELECT \n CAST(strftime('%s', date(dc.pr_date, 'weekday 0', '-6 days')) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY date(dc.pr_date, 'weekday 0', '-6 days'), metric\nORDER BY time ASC", "queryType": "table", - "rawQueryText": "-- Internal Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (Internal)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nUNION ALL\n\n-- External Time to First Review\nSELECT \n CAST(strftime('%s', date(first_response)) as INTEGER) as time,\n repo || ' (External)' as metric,\n AVG((julianday(first_response) - julianday(created_at)) * 24) \n OVER (PARTITION BY repo ORDER BY date(first_response) ROWS BETWEEN 13 PRECEDING AND CURRENT ROW) as value\nFROM (\n SELECT \n pr.repo,\n pr.number,\n pr.created_at,\n MIN(CASE \n WHEN reviews.submitted_at IS NOT NULL THEN reviews.submitted_at\n WHEN comments.created_at IS NOT NULL THEN comments.created_at\n END) as first_response\n FROM pull_requests pr\n LEFT JOIN pr_reviews reviews ON pr.repo = reviews.repo AND pr.number = reviews.pr_number\n LEFT JOIN pr_review_comments comments ON pr.repo = comments.repo AND pr.number = comments.pr_number\n WHERE json_extract(pr.data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n GROUP BY pr.repo, pr.number\n HAVING first_response IS NOT NULL\n) responses\nWHERE repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(first_response)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(first_response)) as INTEGER) <= $__to / 1000\n\nORDER BY time ASC", + "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY date(date(created_at), 'weekday 0', '-6 days'), author\n)\nSELECT \n CAST(strftime('%s', date(dc.pr_date, 'weekday 0', '-6 days')) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY date(dc.pr_date, 'weekday 0', '-6 days'), metric\nORDER BY time ASC", "refId": "A", "timeColumns": [ "time", "ts" ] - }, - { - "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'", - "queryType": "table", - "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'time_to_first_review_hours'", - "refId": "Goal", - "timeColumns": [ - "time" - ] } ], - "title": "Time to First Review (14-Day Rolling)", + "title": "New vs Returning Contributors", "transformations": [ { "id": "prepareTimeSeries", @@ -10780,25 +7127,12 @@ ], "type": "timeseries" }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 95 - }, - "id": 104, - "panels": [], - "title": "Contributor Insights", - "type": "row" - }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "⏱️ Follows date range. Daily count of first-time vs returning contributors.", + "description": "\u23f1\ufe0f Follows date range. Percentage of contributors from 30-60 days ago who returned in last 30 days.", "fieldConfig": { "defaults": { "color": { @@ -10808,12 +7142,12 @@ "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", - "axisLabel": "", + "axisLabel": "Retention %", "axisPlacement": "auto", "barAlignment": 0, "barWidthFactor": 0.6, - "drawStyle": "bars", - "fillOpacity": 80, + "drawStyle": "line", + "fillOpacity": 20, "gradientMode": "none", "hideFrom": { "legend": false, @@ -10821,8 +7155,8 @@ "viz": false }, "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, + "lineInterpolation": "smooth", + "lineWidth": 2, "pointSize": 5, "scaleDistribution": { "type": "linear" @@ -10831,13 +7165,130 @@ "spanNulls": false, "stacking": { "group": "A", - "mode": "normal" + "mode": "none" }, "thresholdsStyle": { - "mode": "off" + "mode": "dashed" } }, "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 17.5 + }, + { + "color": "green", + "value": 25.0 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 94 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "mean", + "last" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "WITH date_series AS (\n SELECT DISTINCT date(date, 'weekday 0', '-6 days') as date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "queryType": "table", + "rawQueryText": "WITH date_series AS (\n SELECT DISTINCT date(date, 'weekday 0', '-6 days') as date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "hide": true, + "queryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'contributor_retention_min'", + "queryType": "table", + "rawQueryText": "SELECT warning_value as \"Warning\", goal_value as \"Critical\" FROM goal_thresholds WHERE metric = 'contributor_retention_min'", + "refId": "Thresholds", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Contributor Retention Rate", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + }, + { + "id": "configFromData", + "options": { + "configRefId": "Thresholds", + "mappings": [ + { + "fieldName": "Warning", + "handlerKey": "threshold1", + "reducerId": "lastNotNull" + }, + { + "fieldName": "Critical", + "handlerKey": "threshold2", + "reducerId": "lastNotNull" + } + ] + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. Leaderboard of community contributors by PR count.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], "thresholds": { "mode": "absolute", "steps": [ @@ -10852,62 +7303,155 @@ { "matcher": { "id": "byName", - "options": "New Contributors" + "options": "pr_count" }, "properties": [ { - "id": "color", + "id": "custom.cellOptions", "value": { - "fixedColor": "green", - "mode": "fixed" + "mode": "gradient", + "type": "gauge" } + }, + { + "id": "min", + "value": 0 } ] }, { "matcher": { "id": "byName", - "options": "Returning Contributors" + "options": "repos" }, "properties": [ { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } + "id": "custom.width", + "value": 300 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 102 + }, + "id": 23, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "pr_count" + } + ] + }, + "targets": [ + { + "queryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", + "queryType": "table", + "rawQueryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Top Community Contributors", + "type": "table" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "\u23f1\ufe0f Follows date range. Community contributor count per repository.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null } ] } - ] + }, + "overrides": [] }, "gridPos": { - "h": 8, + "h": 10, "w": 12, - "x": 0, - "y": 96 + "x": 12, + "y": 102 }, - "id": 21, + "id": 24, "options": { + "barRadius": 0.1, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, "legend": { - "calcs": [ - "sum" - ], + "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", "tooltip": { "hideZeros": false, - "mode": "multi", + "mode": "single", "sort": "none" - } + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 100 }, "targets": [ { - "queryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n GROUP BY date(created_at), author\n)\nSELECT \n CAST(strftime('%s', dc.pr_date) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY dc.pr_date, metric\nORDER BY dc.pr_date ASC", + "queryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", "queryType": "table", - "rawQueryText": "WITH first_contributions AS (\n SELECT \n author,\n MIN(date(created_at)) as first_pr_date\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY author\n),\ndaily_contributors AS (\n SELECT \n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n GROUP BY date(created_at), author\n)\nSELECT \n CAST(strftime('%s', dc.pr_date) as INTEGER) as time,\n CASE WHEN fc.first_pr_date = dc.pr_date THEN 'New Contributors' ELSE 'Returning Contributors' END as metric,\n COUNT(DISTINCT dc.author) as value\nFROM daily_contributors dc\nJOIN first_contributions fc ON dc.author = fc.author\nWHERE CAST(strftime('%s', dc.pr_date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', dc.pr_date) as INTEGER) <= $__to / 1000\nGROUP BY dc.pr_date, metric\nORDER BY dc.pr_date ASC", + "rawQueryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", "refId": "A", "timeColumns": [ "time", @@ -10915,23 +7459,16 @@ ] } ], - "title": "New vs Returning Contributors", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries" + "title": "Unique Contributors by Repository", + "transformations": [], + "type": "barchart" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "⏱️ Follows date range. Percentage of contributors from 30-60 days ago who returned in last 30 days.", + "description": "\u23f1\ufe0f Follows date range. Running total of first-time community contributors over time.", "fieldConfig": { "defaults": { "color": { @@ -10941,13 +7478,13 @@ "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", - "axisLabel": "Retention %", + "axisLabel": "Total Contributors", "axisPlacement": "auto", "barAlignment": 0, "barWidthFactor": 0.6, "drawStyle": "line", - "fillOpacity": 20, - "gradientMode": "none", + "fillOpacity": 30, + "gradientMode": "opacity", "hideFrom": { "legend": false, "tooltip": false, @@ -10960,7 +7497,7 @@ "scaleDistribution": { "type": "linear" }, - "showPoints": "auto", + "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", @@ -10971,74 +7508,28 @@ } }, "mappings": [], - "max": 100, - "min": 0, "thresholds": { "mode": "absolute", "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "yellow", - "value": 17.5 - }, { "color": "green", - "value": 25.0 - } - ] - }, - "unit": "percent" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Goal (25%)" - }, - "properties": [ - { - "id": "custom.lineStyle", - "value": { - "dash": [ - 10, - 10 - ], - "fill": "dash" - } - }, - { - "id": "custom.lineWidth", - "value": 2 - }, - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - }, - { - "id": "custom.fillOpacity", - "value": 0 + "value": null } ] } - ] + }, + "overrides": [] }, "gridPos": { "h": 8, - "w": 12, - "x": 12, - "y": 96 + "w": 24, + "x": 0, + "y": 112 }, - "id": 22, + "id": 25, "options": { "legend": { "calcs": [ - "mean", "last" ], "displayMode": "list", @@ -11053,26 +7544,17 @@ }, "targets": [ { - "queryText": "WITH date_series AS (\n SELECT DISTINCT date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "queryText": "SELECT\n CAST(strftime('%s', week_start) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n cumulative_community_contributors as value\nFROM (\n SELECT\n date(date, 'weekday 0', '-6 days') as week_start,\n cumulative_community_contributors,\n ROW_NUMBER() OVER (PARTITION BY date(date, 'weekday 0', '-6 days') ORDER BY date DESC) as rn\n FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n) WHERE rn = 1\nORDER BY week_start ASC", "queryType": "table", - "rawQueryText": "WITH date_series AS (\n SELECT DISTINCT date FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n),\ncontributor_activity AS (\n SELECT DISTINCT\n date(created_at) as pr_date,\n author\n FROM pull_requests\n WHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n),\nprior_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-60 days') \n AND ca.pr_date <= date(ds.date, '-30 days')\n GROUP BY ds.date, ca.author\n),\ncurrent_period AS (\n SELECT \n ds.date as ref_date,\n ca.author\n FROM date_series ds\n JOIN contributor_activity ca \n ON ca.pr_date > date(ds.date, '-30 days') \n AND ca.pr_date <= ds.date\n GROUP BY ds.date, ca.author\n),\nretention_calc AS (\n SELECT \n pp.ref_date,\n COUNT(DISTINCT pp.author) as prior_contributors,\n COUNT(DISTINCT CASE WHEN cp.author IS NOT NULL THEN pp.author END) as retained\n FROM prior_period pp\n LEFT JOIN current_period cp ON pp.ref_date = cp.ref_date AND pp.author = cp.author\n GROUP BY pp.ref_date\n)\nSELECT \n CAST(strftime('%s', ref_date) as INTEGER) as time,\n 'Retention Rate' as metric,\n CASE \n WHEN prior_contributors = 0 THEN 0 \n ELSE ROUND(100.0 * retained / prior_contributors, 1) \n END as value\nFROM retention_calc\nORDER BY ref_date", + "rawQueryText": "SELECT\n CAST(strftime('%s', week_start) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n cumulative_community_contributors as value\nFROM (\n SELECT\n date(date, 'weekday 0', '-6 days') as week_start,\n cumulative_community_contributors,\n ROW_NUMBER() OVER (PARTITION BY date(date, 'weekday 0', '-6 days') ORDER BY date DESC) as rn\n FROM daily_metrics\n WHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n) WHERE rn = 1\nORDER BY week_start ASC", "refId": "A", "timeColumns": [ "time", "ts" ] - }, - { - "queryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'", - "queryType": "table", - "rawQueryText": "SELECT $__from / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'\nUNION ALL\nSELECT $__to / 1000 as time, label as metric, value FROM goals WHERE metric = 'contributor_retention_min'", - "refId": "Goal", - "timeColumns": [ - "time" - ] } ], - "title": "Contributor Retention Rate", + "title": "Cumulative Community Contributors", "transformations": [ { "id": "prepareTimeSeries", @@ -11083,24 +7565,30 @@ ], "type": "timeseries" }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 300, + "panels": [], + "title": "Adoption", + "type": "row" + }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "⏱️ Follows date range. Leaderboard of community contributors by PR count.", + "description": "Total all-time downloads across all packages and registries. Note: Download data is ~24h delayed (PyPI/npm update daily).", "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, - "custom": { - "align": "auto", - "cellOptions": { - "type": "auto" - }, - "inspect": false - }, "mappings": [], "thresholds": { "mode": "absolute", @@ -11110,178 +7598,224 @@ "value": null } ] - } + }, + "unit": "short" }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "pr_count" - }, - "properties": [ - { - "id": "custom.cellOptions", - "value": { - "mode": "gradient", - "type": "gauge" - } - }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 7 + }, + "id": 301, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "Total Downloads (All-Time)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Downloads in the last 7 days across all packages. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ { - "id": "min", - "value": 0 + "color": "blue", + "value": null } ] }, - { - "matcher": { - "id": "byName", - "options": "repos" - }, - "properties": [ + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 7 + }, + "id": 302, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto" + }, + "targets": [ + { + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", + "queryType": "table", + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" + } + ], + "title": "Downloads (7d)", + "type": "stat" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Total PyPI (Python) downloads all-time. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ { - "id": "custom.width", - "value": 300 + "color": "yellow", + "value": null } ] - } - ] + }, + "unit": "short" + }, + "overrides": [] }, "gridPos": { - "h": 10, - "w": 12, - "x": 0, - "y": 104 + "h": 4, + "w": 4, + "x": 8, + "y": 7 }, - "id": 23, + "id": 303, "options": { - "cellHeight": "sm", - "footer": { - "countRows": false, - "fields": "", - "reducer": [ - "sum" + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" ], - "show": false + "fields": "", + "values": false }, - "showHeader": true, - "sortBy": [ - { - "desc": true, - "displayName": "pr_count" - } - ] + "showPercentChange": false, + "textMode": "auto" }, "targets": [ { - "queryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'pypi'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','tools','agent-sop','agent-builder','evals')))", "queryType": "table", - "rawQueryText": "SELECT \n author,\n COUNT(*) as pr_count,\n GROUP_CONCAT(DISTINCT repo) as repos\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY author\nORDER BY pr_count DESC\nLIMIT 20", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'pypi'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" } ], - "title": "Top Community Contributors", - "type": "table" + "title": "PyPI Downloads", + "type": "stat" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "⏱️ Follows date range. Community contributor count per repository.", + "description": "Total npm (TypeScript) downloads all-time. Note: Download data is ~24h delayed (PyPI/npm update daily).", "fieldConfig": { "defaults": { "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1, - "scaleDistribution": { - "type": "linear" - }, - "thresholdsStyle": { - "mode": "off" - } + "mode": "thresholds" }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { - "color": "green", + "color": "orange", "value": null } ] - } + }, + "unit": "short" }, "overrides": [] }, "gridPos": { - "h": 10, - "w": 12, + "h": 4, + "w": 4, "x": 12, - "y": 104 + "y": 7 }, - "id": 24, + "id": 304, "options": { - "barRadius": 0.1, - "barWidth": 0.8, - "fullHighlight": false, - "groupWidth": 0.7, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "orientation": "horizontal", - "showValue": "always", - "stacking": "none", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 100 + "showPercentChange": false, + "textMode": "auto" }, "targets": [ { - "queryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", + "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'npm'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-typescript'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-typescript')))", "queryType": "table", - "rawQueryText": "SELECT \n repo,\n COUNT(DISTINCT author) as unique_contributors\nFROM pull_requests\nWHERE json_extract(data, '$.author_association') NOT IN ('OWNER', 'MEMBER', 'COLLABORATOR')\n AND author NOT LIKE '%[bot]%'\n AND author NOT IN ('strands-agent', 'dependabot')\n AND repo IN (${repo:singlequote})\n AND CAST(strftime('%s', date(created_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(created_at)) as INTEGER) <= $__to / 1000\nGROUP BY repo\nORDER BY unique_contributors DESC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] + "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'npm'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "refId": "A" } ], - "title": "Unique Contributors by Repository", - "transformations": [], - "type": "barchart" + "title": "npm Downloads", + "type": "stat" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "⏱️ Follows date range. Running total of first-time community contributors over time.", + "description": "Daily download counts by package. PyPI retains 180 days, npm retains 365+ days. Note: Download data is ~24h delayed (PyPI/npm update daily).", "fieldConfig": { "defaults": { "color": { @@ -11289,15 +7823,12 @@ }, "custom": { "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "Total Contributors", + "axisLabel": "Downloads", "axisPlacement": "auto", "barAlignment": 0, - "barWidthFactor": 0.6, "drawStyle": "line", - "fillOpacity": 30, - "gradientMode": "opacity", + "fillOpacity": 10, + "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, @@ -11335,215 +7866,217 @@ }, "gridPos": { "h": 8, - "w": 24, + "w": 12, "x": 0, - "y": 114 + "y": 11 }, - "id": 25, + "id": 305, "options": { "legend": { "calcs": [ - "last" + "sum" ], - "displayMode": "list", - "placement": "bottom", + "displayMode": "table", + "placement": "right", "showLegend": true }, "tooltip": { "hideZeros": false, - "mode": "single", - "sort": "none" + "mode": "multi", + "sort": "desc" } }, "targets": [ { - "queryText": "SELECT\n CAST(strftime('%s', date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n cumulative_community_contributors as value\nFROM daily_metrics\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date\nORDER BY date ASC", + "queryText": "SELECT \n CAST(strftime('%s', date(pd.date, 'weekday 0', '-6 days')) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY date(pd.date, 'weekday 0', '-6 days'), pd.package\nORDER BY time, pd.package", "queryType": "table", - "rawQueryText": "SELECT\n CAST(strftime('%s', date) as INTEGER) as time,\n 'Cumulative Contributors' as metric,\n cumulative_community_contributors as value\nFROM daily_metrics\nWHERE CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date\nORDER BY date ASC", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(pd.date, 'weekday 0', '-6 days')) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY date(pd.date, 'weekday 0', '-6 days'), pd.package\nORDER BY time, pd.package", "refId": "A", "timeColumns": [ - "time", - "ts" + "time" ] } ], - "title": "Cumulative Community Contributors", + "title": "Weekly Downloads by Package", "transformations": [ { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ], - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 6 - }, - "id": 300, - "panels": [], - "title": "Adoption", - "type": "row" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "Total all-time downloads across all packages and registries. Note: Download data is ~24h delayed (PyPI/npm update daily).", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 4, - "w": 4, - "x": 0, - "y": 7 - }, - "id": 301, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showPercentChange": false, - "textMode": "auto" - }, - "targets": [ - { - "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", - "queryType": "table", - "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", - "refId": "A" + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } } ], - "title": "Total Downloads (All-Time)", - "type": "stat" + "type": "timeseries" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "Downloads in the last 7 days across all packages. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "description": "Cumulative downloads over time showing growth trajectory. Note: Download data is ~24h delayed (PyPI/npm update daily).", "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Total Downloads", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { - "color": "blue", + "color": "green", "value": null } ] - }, - "unit": "short" + } }, "overrides": [] }, "gridPos": { - "h": 4, - "w": 4, - "x": 4, - "y": 7 + "h": 8, + "w": 12, + "x": 12, + "y": 11 }, - "id": 302, + "id": 306, "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { + "legend": { "calcs": [ "lastNotNull" ], - "fields": "", - "values": false + "displayMode": "table", + "placement": "right", + "showLegend": true }, - "showPercentChange": false, - "textMode": "auto" + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } }, "targets": [ { - "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))", + "queryText": "SELECT \n CAST(strftime('%s', date(pd.date, 'weekday 0', '-6 days')) as INTEGER) as time,\n pd.package as metric,\n SUM(SUM(pd.downloads)) OVER (PARTITION BY pd.package ORDER BY date(pd.date, 'weekday 0', '-6 days')) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY date(pd.date, 'weekday 0', '-6 days'), pd.package\nORDER BY time, pd.package", "queryType": "table", - "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' \n AND pd.date >= date('now', '-7 days')\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", - "refId": "A" + "rawQueryText": "SELECT \n CAST(strftime('%s', date(pd.date, 'weekday 0', '-6 days')) as INTEGER) as time,\n pd.package as metric,\n SUM(SUM(pd.downloads)) OVER (PARTITION BY pd.package ORDER BY date(pd.date, 'weekday 0', '-6 days')) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY date(pd.date, 'weekday 0', '-6 days'), pd.package\nORDER BY time, pd.package", + "refId": "A", + "timeColumns": [ + "time" + ] } ], - "title": "Downloads (7d)", - "type": "stat" + "title": "Cumulative Downloads by Package", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "Total PyPI (Python) downloads all-time. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "description": "Download distribution by registry (PyPI vs npm). Note: Download data is ~24h delayed (PyPI/npm update daily).", "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pypi" + }, + "properties": [ { - "color": "yellow", - "value": null + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } } ] }, - "unit": "short" - }, - "overrides": [] + { + "matcher": { + "id": "byName", + "options": "npm" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + } + ] }, "gridPos": { - "h": 4, - "w": 4, - "x": 8, - "y": 7 + "h": 8, + "w": 6, + "x": 0, + "y": 19 }, - "id": 303, + "id": 307, "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true, + "values": [ + "value", + "percent" + ] + }, + "pieType": "donut", "reduceOptions": { "calcs": [ "lastNotNull" @@ -11551,84 +8084,126 @@ "fields": "", "values": false }, - "showPercentChange": false, - "textMode": "auto" + "tooltip": { + "mode": "single", + "sort": "none" + } }, "targets": [ { - "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'pypi'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','tools','agent-sop','agent-builder','evals')))", + "queryText": "SELECT pd.registry, SUM(pd.downloads) as count\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY pd.registry", "queryType": "table", - "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'pypi'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "rawQueryText": "SELECT pd.registry, SUM(pd.downloads) as count\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY pd.registry", "refId": "A" } ], - "title": "PyPI Downloads", - "type": "stat" + "title": "Downloads by Registry", + "transformations": [ + { + "id": "rowsToFields", + "options": { + "mappings": [ + { + "fieldName": "registry", + "handlerKey": "field.name" + }, + { + "fieldName": "count", + "handlerKey": "field.value" + } + ] + } + } + ], + "type": "piechart" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "Total npm (TypeScript) downloads all-time. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "description": "Downloads per package for selected time range. Note: Download data is ~24h delayed (PyPI/npm update daily).", "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisLabel": "Downloads", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { - "color": "orange", + "color": "green", "value": null } ] - }, - "unit": "short" + } }, "overrides": [] }, "gridPos": { - "h": 4, - "w": 4, - "x": 12, - "y": 7 + "h": 8, + "w": 10, + "x": 6, + "y": 19 }, - "id": 304, + "id": 308, "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false + "barRadius": 0.1, + "barWidth": 0.8, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "showPercentChange": false, - "textMode": "auto" + "orientation": "horizontal", + "showValue": "always", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } }, "targets": [ { - "queryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'npm'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-typescript'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-typescript')))", + "queryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY pd.package\nORDER BY downloads DESC", "queryType": "table", - "rawQueryText": "SELECT SUM(pd.downloads) as value \nFROM package_downloads pd\nWHERE pd.version = 'total' AND pd.registry = 'npm'\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))", + "rawQueryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY pd.package\nORDER BY downloads DESC", "refId": "A" } ], - "title": "npm Downloads", - "type": "stat" + "title": "Downloads by Package", + "type": "barchart" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "Daily download counts by package. PyPI retains 180 days, npm retains 365+ days. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "description": "Week-over-week download trends by registry. Note: Download data is ~24h delayed (PyPI/npm update daily).", "fieldConfig": { "defaults": { "color": { @@ -11636,11 +8211,12 @@ }, "custom": { "axisBorderShow": false, + "axisCenteredZero": true, "axisLabel": "Downloads", "axisPlacement": "auto", "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, + "drawStyle": "bars", + "fillOpacity": 80, "gradientMode": "none", "hideFrom": { "legend": false, @@ -11648,17 +8224,17 @@ "viz": false }, "insertNulls": false, - "lineInterpolation": "smooth", - "lineWidth": 2, + "lineInterpolation": "linear", + "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, - "showPoints": "never", + "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", - "mode": "none" + "mode": "normal" }, "thresholdsStyle": { "mode": "off" @@ -11679,18 +8255,18 @@ }, "gridPos": { "h": 8, - "w": 12, - "x": 0, - "y": 11 + "w": 8, + "x": 16, + "y": 19 }, - "id": 305, + "id": 309, "options": { "legend": { "calcs": [ "sum" ], "displayMode": "table", - "placement": "right", + "placement": "bottom", "showLegend": true }, "tooltip": { @@ -11701,16 +8277,16 @@ }, "targets": [ { - "queryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n pd.downloads as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nORDER BY pd.date, pd.package", + "queryText": "SELECT \n CAST(strftime('%s', strftime('%Y-%m-%d', pd.date, 'weekday 0', '-6 days')) as INTEGER) as time,\n pd.registry as metric,\n SUM(pd.downloads) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY strftime('%Y-%W', pd.date), pd.registry\nORDER BY time", "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n pd.downloads as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nORDER BY pd.date, pd.package", + "rawQueryText": "SELECT \n CAST(strftime('%s', strftime('%Y-%m-%d', pd.date, 'weekday 0', '-6 days')) as INTEGER) as time,\n pd.registry as metric,\n SUM(pd.downloads) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY strftime('%Y-%W', pd.date), pd.registry\nORDER BY time", "refId": "A", "timeColumns": [ "time" ] } ], - "title": "Daily Downloads by Package", + "title": "Weekly Downloads by Registry", "transformations": [ { "id": "prepareTimeSeries", @@ -11726,48 +8302,18 @@ "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "Cumulative downloads over time showing growth trajectory. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "description": "Current count of open pull requests per repository.", "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, - "custom": { - "axisBorderShow": false, - "axisLabel": "Total Downloads", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 20, - "gradientMode": "opacity", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "smooth", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { - "color": "green", + "color": "blue", "value": null } ] @@ -11776,247 +8322,354 @@ "overrides": [] }, "gridPos": { - "h": 8, + "h": 6, "w": 12, - "x": 12, - "y": 11 + "x": 0, + "y": 28 }, - "id": 306, + "id": 310, "options": { - "legend": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { "calcs": [ "lastNotNull" ], - "displayMode": "table", - "placement": "right", - "showLegend": true + "fields": "", + "values": true }, - "tooltip": { - "hideZeros": false, - "mode": "multi", - "sort": "desc" - } + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" }, "targets": [ { - "queryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) OVER (PARTITION BY pd.package ORDER BY pd.date) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nORDER BY pd.date, pd.package", + "queryText": "SELECT repo, COUNT(*) as count FROM pull_requests WHERE state = 'open' AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') GROUP BY repo ORDER BY count DESC", "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', pd.date) as INTEGER) as time,\n pd.package as metric,\n SUM(pd.downloads) OVER (PARTITION BY pd.package ORDER BY pd.date) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nORDER BY pd.date, pd.package", + "rawQueryText": "SELECT repo, COUNT(*) as count FROM pull_requests WHERE state = 'open' AND repo IN (${repo:singlequote}) GROUP BY repo ORDER BY count DESC", "refId": "A", "timeColumns": [ - "time" + "time", + "ts" ] } ], - "title": "Cumulative Downloads by Package", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" + "title": "Open PRs by Repository", + "type": "bargauge" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Current count of open issues per repository.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 311, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "targets": [ + { + "queryText": "SELECT repo, COUNT(*) as count FROM issues WHERE state = 'open' AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') GROUP BY repo ORDER BY count DESC", + "queryType": "table", + "rawQueryText": "SELECT repo, COUNT(*) as count FROM issues WHERE state = 'open' AND repo IN (${repo:singlequote}) GROUP BY repo ORDER BY count DESC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] } ], - "type": "timeseries" + "title": "Open Issues by Repository", + "type": "bargauge" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "Download distribution by registry (PyPI vs npm). Note: Download data is ~24h delayed (PyPI/npm update daily).", + "description": "Opened vs Closed (Merged + Rejected stacked) with net delta line. Stacked green/red shows merge vs rejection breakdown.", "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 30, + "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } }, - "mappings": [] + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } }, "overrides": [ { "matcher": { "id": "byName", - "options": "pypi" + "options": "Opened" }, "properties": [ { "id": "color", "value": { - "fixedColor": "yellow", + "fixedColor": "light-blue", "mode": "fixed" } + }, + { + "id": "custom.stacking", + "value": { + "group": "Opened", + "mode": "none" + } } ] }, { "matcher": { "id": "byName", - "options": "npm" + "options": "Merged" }, "properties": [ { "id": "color", "value": { - "fixedColor": "orange", + "fixedColor": "semi-dark-green", "mode": "fixed" } + }, + { + "id": "custom.stacking", + "value": { + "group": "Closed", + "mode": "normal" + } } ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 6, - "x": 0, - "y": 19 - }, - "id": 307, - "options": { - "legend": { - "displayMode": "table", - "placement": "right", - "showLegend": true, - "values": [ - "value", - "percent" - ] - }, - "pieType": "donut", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "queryText": "SELECT pd.registry, SUM(pd.downloads) as count\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY pd.registry", - "queryType": "table", - "rawQueryText": "SELECT pd.registry, SUM(pd.downloads) as count\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY pd.registry", - "refId": "A" - } - ], - "title": "Downloads by Registry", - "transformations": [ - { - "id": "rowsToFields", - "options": { - "mappings": [ + }, + { + "matcher": { + "id": "byName", + "options": "Rejected" + }, + "properties": [ { - "fieldName": "registry", - "handlerKey": "field.name" + "id": "color", + "value": { + "fixedColor": "light-red", + "mode": "fixed" + } }, { - "fieldName": "count", - "handlerKey": "field.value" + "id": "custom.stacking", + "value": { + "group": "Closed", + "mode": "normal" + } } ] - } - } - ], - "type": "piechart" - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "Downloads per package for selected time range. Note: Download data is ~24h delayed (PyPI/npm update daily).", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" }, - "custom": { - "axisBorderShow": false, - "axisLabel": "Downloads", - "axisPlacement": "auto", - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1, - "scaleDistribution": { - "type": "linear" + { + "matcher": { + "id": "byName", + "options": "Delta" }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ + "properties": [ { - "color": "green", - "value": null + "id": "color", + "value": { + "fixedColor": "white", + "mode": "fixed" + } + }, + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.lineStyle", + "value": { + "fill": "dash", + "dash": [ + 10, + 5 + ] + } + }, + { + "id": "custom.showPoints", + "value": "always" + }, + { + "id": "custom.pointSize", + "value": 6 + }, + { + "id": "custom.stacking", + "value": { + "group": "Delta", + "mode": "none" + } } ] } - }, - "overrides": [] + ] }, "gridPos": { "h": 8, - "w": 10, - "x": 6, - "y": 19 + "w": 12, + "x": 0, + "y": 34 }, - "id": 308, + "id": 312, "options": { - "barRadius": 0.1, - "barWidth": 0.8, - "fullHighlight": false, - "groupWidth": 0.7, "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom", - "showLegend": false + "placement": "bottom" }, - "orientation": "horizontal", - "showValue": "always", - "stacking": "none", "tooltip": { - "hideZeros": false, - "mode": "single", + "mode": "multi", "sort": "none" } }, "targets": [ { - "queryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY pd.package\nORDER BY downloads DESC", + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(prs_opened) as \"Opened\"\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time ASC", "queryType": "table", - "rawQueryText": "SELECT pd.package, SUM(pd.downloads) as downloads\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY pd.package\nORDER BY downloads DESC", - "refId": "A" + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(prs_opened) as \"Opened\"\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(prs_merged) as \"Merged\"\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(prs_merged) as \"Merged\"\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time ASC", + "refId": "B", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n COUNT(*) as \"Rejected\"\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(closed_at), 'weekday 0', '-6 days')\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n COUNT(*) as \"Rejected\"\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(closed_at), 'weekday 0', '-6 days')\nORDER BY time ASC", + "refId": "C", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT \n dm.week as time,\n dm.opened - dm.merged - COALESCE(rej.rejected, 0) as \"Delta\"\nFROM (\n SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as week,\n SUM(prs_opened) as opened,\n SUM(prs_merged) as merged\n FROM daily_metrics \n WHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n GROUP BY date(date, 'weekday 0', '-6 days')\n) dm\nLEFT JOIN (\n SELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as week,\n COUNT(*) as rejected\n FROM pull_requests\n WHERE state = 'closed' AND merged_at IS NULL \n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\n GROUP BY date(date(closed_at), 'weekday 0', '-6 days')\n) rej ON dm.week = rej.week\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n dm.week as time,\n dm.opened - dm.merged - COALESCE(rej.rejected, 0) as \"Delta\"\nFROM (\n SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as week,\n SUM(prs_opened) as opened,\n SUM(prs_merged) as merged\n FROM daily_metrics \n WHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\n GROUP BY date(date, 'weekday 0', '-6 days')\n) dm\nLEFT JOIN (\n SELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as week,\n COUNT(*) as rejected\n FROM pull_requests\n WHERE state = 'closed' AND merged_at IS NULL \n AND repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\n GROUP BY date(date(closed_at), 'weekday 0', '-6 days')\n) rej ON dm.week = rej.week\nORDER BY time ASC", + "refId": "D", + "timeColumns": [ + "time", + "ts" + ] } ], - "title": "Downloads by Package", - "type": "barchart" + "title": "PR Velocity (Weekly)", + "type": "timeseries" }, { "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "Week-over-week download trends by registry. Note: Download data is ~24h delayed (PyPI/npm update daily).", + "description": "Issues opened and closed per week with net delta line.", "fieldConfig": { "defaults": { "color": { @@ -12024,12 +8677,14 @@ }, "custom": { "axisBorderShow": false, - "axisCenteredZero": true, - "axisLabel": "Downloads", + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", - "fillOpacity": 80, + "fillOpacity": 30, "gradientMode": "none", "hideFrom": { "legend": false, @@ -12043,11 +8698,11 @@ "scaleDistribution": { "type": "linear" }, - "showPoints": "auto", + "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", - "mode": "normal" + "mode": "none" }, "thresholdsStyle": { "mode": "off" @@ -12064,50 +8719,135 @@ ] } }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Opened" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Closed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Delta" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "white", + "mode": "fixed" + } + }, + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.lineStyle", + "value": { + "fill": "dash", + "dash": [ + 10, + 5 + ] + } + }, + { + "id": "custom.showPoints", + "value": "always" + }, + { + "id": "custom.pointSize", + "value": 6 + } + ] + } + ] }, "gridPos": { "h": 8, - "w": 8, - "x": 16, - "y": 19 + "w": 12, + "x": 12, + "y": 34 }, - "id": 309, + "id": 313, "options": { "legend": { - "calcs": [ - "sum" - ], - "displayMode": "table", - "placement": "bottom", - "showLegend": true + "calcs": [], + "displayMode": "list", + "placement": "bottom" }, "tooltip": { - "hideZeros": false, "mode": "multi", - "sort": "desc" + "sort": "none" } }, "targets": [ { - "queryText": "SELECT \n CAST(strftime('%s', strftime('%Y-%m-%d', pd.date, 'weekday 0', '-6 days')) as INTEGER) as time,\n pd.registry as metric,\n SUM(pd.downloads) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals'))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN ('sdk-python','sdk-typescript','tools','agent-sop','agent-builder','evals')))\nGROUP BY strftime('%Y-%W', pd.date), pd.registry\nORDER BY time", + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(issues_opened) as \"Opened\"\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time ASC", "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', strftime('%Y-%m-%d', pd.date, 'weekday 0', '-6 days')) as INTEGER) as time,\n pd.registry as metric,\n SUM(pd.downloads) as value\nFROM package_downloads pd\nWHERE pd.version = 'total'\n AND CAST(strftime('%s', pd.date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pd.date) as INTEGER) <= $__to / 1000\n AND (pd.package IN (SELECT package FROM repo_package_mapping WHERE repo IN (${repo:singlequote}))\n OR NOT EXISTS (SELECT 1 FROM repo_package_mapping WHERE repo IN (${repo:singlequote})))\nGROUP BY strftime('%Y-%W', pd.date), pd.registry\nORDER BY time", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(issues_opened) as \"Opened\"\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time ASC", "refId": "A", "timeColumns": [ - "time" + "time", + "ts" ] - } - ], - "title": "Weekly Downloads by Registry", - "transformations": [ + }, { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(issues_closed) as \"Closed\"\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(issues_closed) as \"Closed\"\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time ASC", + "refId": "B", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(issues_opened) - SUM(issues_closed) as \"Delta\"\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n SUM(issues_opened) - SUM(issues_closed) as \"Delta\"\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days')\nORDER BY time ASC", + "refId": "C", + "timeColumns": [ + "time", + "ts" + ] } ], + "title": "Issue Velocity (Weekly)", "type": "timeseries" } ], @@ -12153,7 +8893,7 @@ ] }, "time": { - "from": "now-30d", + "from": "now-42d", "to": "now" }, "timepicker": {}, @@ -12161,4 +8901,4 @@ "title": "Overview", "uid": "adj9pgt", "version": 10 -} \ No newline at end of file +} From 6492933542838081541be0c7e0fecac1291eb06b Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Thu, 26 Feb 2026 22:06:14 -0500 Subject: [PATCH 14/22] feat(community-dashboard): add detailed breakdown to volume --- .../dashboards/general/health.json | 3756 ++++++++++++++++- 1 file changed, 3731 insertions(+), 25 deletions(-) diff --git a/community-dashboard/provisioning/dashboards/general/health.json b/community-dashboard/provisioning/dashboards/general/health.json index a3aa8a9..f630ca9 100644 --- a/community-dashboard/provisioning/dashboards/general/health.json +++ b/community-dashboard/provisioning/dashboards/general/health.json @@ -550,7 +550,7 @@ "h": 1, "w": 24, "x": 0, - "y": 42 + "y": 58 }, "id": 101, "panels": [], @@ -563,7 +563,7 @@ "h": 1, "w": 24, "x": 0, - "y": 59 + "y": 75 }, "id": 102, "panels": [], @@ -576,7 +576,7 @@ "h": 1, "w": 24, "x": 0, - "y": 76 + "y": 92 }, "id": 103, "panels": [], @@ -1475,7 +1475,7 @@ "h": 8, "w": 12, "x": 0, - "y": 77 + "y": 93 }, "id": 12, "options": { @@ -2407,7 +2407,7 @@ "h": 8, "w": 12, "x": 12, - "y": 77 + "y": 93 }, "id": 10, "options": { @@ -2677,7 +2677,7 @@ "h": 8, "w": 12, "x": 0, - "y": 85 + "y": 101 }, "id": 18, "options": { @@ -3623,7 +3623,7 @@ "h": 8, "w": 12, "x": 12, - "y": 85 + "y": 101 }, "id": 9, "options": { @@ -3891,7 +3891,7 @@ "h": 8, "w": 12, "x": 12, - "y": 51 + "y": 67 }, "id": 19, "options": { @@ -4175,7 +4175,7 @@ "h": 8, "w": 12, "x": 0, - "y": 60 + "y": 76 }, "id": 13, "options": { @@ -4470,7 +4470,7 @@ "h": 8, "w": 12, "x": 0, - "y": 68 + "y": 84 }, "id": 14, "options": { @@ -4746,7 +4746,7 @@ "h": 8, "w": 12, "x": 12, - "y": 60 + "y": 76 }, "id": 15, "options": { @@ -5041,7 +5041,7 @@ "h": 8, "w": 12, "x": 12, - "y": 68 + "y": 84 }, "id": 16, "options": { @@ -5976,7 +5976,7 @@ "h": 8, "w": 12, "x": 0, - "y": 51 + "y": 67 }, "id": 7, "options": { @@ -6446,7 +6446,7 @@ "h": 8, "w": 12, "x": 0, - "y": 43 + "y": 59 }, "id": 17, "options": { @@ -6914,7 +6914,7 @@ "h": 8, "w": 12, "x": 12, - "y": 43 + "y": 59 }, "id": 20, "options": { @@ -6987,7 +6987,7 @@ "h": 1, "w": 24, "x": 0, - "y": 93 + "y": 109 }, "id": 104, "panels": [], @@ -7086,7 +7086,7 @@ "h": 8, "w": 12, "x": 0, - "y": 94 + "y": 110 }, "id": 21, "options": { @@ -7199,7 +7199,7 @@ "h": 8, "w": 12, "x": 12, - "y": 94 + "y": 110 }, "id": 22, "options": { @@ -7337,7 +7337,7 @@ "h": 10, "w": 12, "x": 0, - "y": 102 + "y": 118 }, "id": 23, "options": { @@ -7422,7 +7422,7 @@ "h": 10, "w": 12, "x": 12, - "y": 102 + "y": 118 }, "id": 24, "options": { @@ -7524,7 +7524,7 @@ "h": 8, "w": 24, "x": 0, - "y": 112 + "y": 128 }, "id": 25, "options": { @@ -8324,7 +8324,7 @@ "gridPos": { "h": 6, "w": 12, - "x": 0, + "x": 12, "y": 28 }, "id": 310, @@ -8388,7 +8388,7 @@ "gridPos": { "h": 6, "w": 12, - "x": 12, + "x": 0, "y": 28 }, "id": 311, @@ -8604,7 +8604,7 @@ "gridPos": { "h": 8, "w": 12, - "x": 0, + "x": 12, "y": 34 }, "id": 312, @@ -8800,7 +8800,7 @@ "gridPos": { "h": 8, "w": 12, - "x": 12, + "x": 0, "y": 34 }, "id": 313, @@ -8849,6 +8849,3712 @@ ], "title": "Issue Velocity (Weekly)", "type": "timeseries" + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Weekly PRs opened per repository, stacked.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 42 + }, + "id": 314, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(prs_opened) as value\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(prs_opened) as value\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PRs Opened by Repo (Weekly)", + "type": "timeseries", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ] + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Weekly PRs merged + rejected per repository, stacked.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 50 + }, + "id": 315, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(prs_merged) as value\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(prs_merged) as value\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(closed_at), 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(closed_at), 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "refId": "B", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "PRs Closed by Repo (Weekly)", + "type": "timeseries", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ] + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Weekly issues opened per repository, stacked.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 42 + }, + "id": 316, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(issues_opened) as value\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(issues_opened) as value\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Opened by Repo (Weekly)", + "type": "timeseries", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ] + }, + { + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "description": "Weekly issues closed per repository, stacked.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "value sdk-python" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-python (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value sdk-typescript (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value tools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value docs (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-builder (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value agent-sop (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value samples (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value mcp-server (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value evals (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value .github (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#808080", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Internal)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (External)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (First Response)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "value devtools (Resolution Time)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 50 + }, + "id": 317, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(issues_closed) as value\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(issues_closed) as value\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "title": "Issues Closed by Repo (Weekly)", + "type": "timeseries", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ] } ], "preload": false, From e6f4a8598ca47ac8d396b13c0a1552749f1f094d Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Thu, 26 Feb 2026 23:17:37 -0500 Subject: [PATCH 15/22] fix: fix triage section --- .../dashboards/general/health.json | 762 +++++++++++++++++- .../strands-metrics/src/client.rs | 155 ++++ community-dashboard/strands-metrics/src/db.rs | 66 +- 3 files changed, 901 insertions(+), 82 deletions(-) diff --git a/community-dashboard/provisioning/dashboards/general/health.json b/community-dashboard/provisioning/dashboards/general/health.json index f630ca9..fec3727 100644 --- a/community-dashboard/provisioning/dashboards/general/health.json +++ b/community-dashboard/provisioning/dashboards/general/health.json @@ -544,13 +544,695 @@ "title": "Volume", "type": "row" }, + { + "id": 318, + "type": "row", + "title": "Triage", + "gridPos": { + "x": 0, + "y": 58, + "h": 1, + "w": 24 + }, + "collapsed": false, + "panels": [] + }, + { + "id": 319, + "type": "stat", + "title": "Untriaged Issues", + "description": "Open issues in project with no priority set.", + "gridPos": { + "x": 0, + "y": 59, + "h": 4, + "w": 6 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed", + "fixedColor": "yellow" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ], + "fields": "" + }, + "orientation": "auto", + "textMode": "auto", + "wideLayout": true, + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "showPercentChange": false + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT COUNT(*) as value FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority IS NULL AND pi.status != 'Done' AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority IS NULL AND pi.status != 'Done' AND i.repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + } + }, + { + "id": 320, + "type": "stat", + "title": "Sev2 Open", + "description": "Open issues with Sev2 priority.", + "gridPos": { + "x": 6, + "y": 59, + "h": 4, + "w": 6 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed", + "fixedColor": "red" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ], + "fields": "" + }, + "orientation": "auto", + "textMode": "auto", + "wideLayout": true, + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "showPercentChange": false + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT COUNT(*) as value FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority = 'Sev2' AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority = 'Sev2' AND i.repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + } + }, + { + "id": 321, + "type": "stat", + "title": "On-Call Open", + "description": "Open issues with On-Call priority.", + "gridPos": { + "x": 12, + "y": 59, + "h": 4, + "w": 6 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed", + "fixedColor": "orange" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ], + "fields": "" + }, + "orientation": "auto", + "textMode": "auto", + "wideLayout": true, + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "showPercentChange": false + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT COUNT(*) as value FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority = 'On-Call' AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority = 'On-Call' AND i.repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + } + }, + { + "id": 322, + "type": "stat", + "title": "High Open", + "description": "Open issues with High priority.", + "gridPos": { + "x": 18, + "y": 59, + "h": 4, + "w": 6 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed", + "fixedColor": "super-light-orange" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ], + "fields": "" + }, + "orientation": "auto", + "textMode": "auto", + "wideLayout": true, + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "showPercentChange": false + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT COUNT(*) as value FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority = 'High' AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority = 'High' AND i.repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + } + }, + { + "id": 323, + "type": "bargauge", + "title": "Untriaged Issues by Repo", + "description": "Open issues with no priority, broken down by repository.", + "gridPos": { + "x": 0, + "y": 63, + "h": 6, + "w": 12 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "values": true, + "calcs": [], + "fields": "" + }, + "orientation": "horizontal", + "displayMode": "gradient", + "showUnfilled": true, + "valueMode": "color", + "sizing": "auto", + "minVizWidth": 8, + "minVizHeight": 16, + "maxVizHeight": 300, + "namePlacement": "auto", + "legend": { + "showLegend": false, + "displayMode": "hidden", + "placement": "bottom" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT i.repo, COUNT(*) as count FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority IS NULL AND pi.status != 'Done' AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') GROUP BY i.repo ORDER BY count DESC", + "queryType": "table", + "rawQueryText": "SELECT i.repo, COUNT(*) as count FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority IS NULL AND pi.status != 'Done' AND i.repo IN (${repo:singlequote}) GROUP BY i.repo ORDER BY count DESC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + } + }, + { + "id": 324, + "type": "bargauge", + "title": "Priority Issues by Repo", + "description": "Open Sev2/On-Call/High issues broken down by repository.", + "gridPos": { + "x": 12, + "y": 63, + "h": 6, + "w": 12 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "values": true, + "calcs": [], + "fields": "" + }, + "orientation": "horizontal", + "displayMode": "gradient", + "showUnfilled": true, + "valueMode": "color", + "sizing": "auto", + "minVizWidth": 8, + "minVizHeight": 16, + "maxVizHeight": 300, + "namePlacement": "auto", + "legend": { + "showLegend": false, + "displayMode": "hidden", + "placement": "bottom" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT i.repo || ' (' || pi.priority || ')' as metric, COUNT(*) as count FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority IN ('Sev2', 'On-Call', 'High') AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') GROUP BY i.repo, pi.priority ORDER BY count DESC", + "queryType": "table", + "rawQueryText": "SELECT i.repo || ' (' || pi.priority || ')' as metric, COUNT(*) as count FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority IN ('Sev2', 'On-Call', 'High') AND i.repo IN (${repo:singlequote}) GROUP BY i.repo, pi.priority ORDER BY count DESC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + } + }, + { + "id": 325, + "type": "row", + "title": "Responsiveness", + "gridPos": { + "x": 0, + "y": 69, + "h": 1, + "w": 24 + }, + "collapsed": false, + "panels": [] + }, + { + "id": 326, + "type": "stat", + "title": "Issues Awaiting Response", + "description": "Open issues from non-maintainers where the last comment is not from a team member.", + "gridPos": { + "x": 0, + "y": 70, + "h": 4, + "w": 12 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed", + "fixedColor": "yellow" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ], + "fields": "" + }, + "orientation": "auto", + "textMode": "auto", + "wideLayout": true, + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "showPercentChange": false + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT COUNT(DISTINCT i.id) as value FROM issues i WHERE i.state = 'open' AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND i.author NOT IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]') AND NOT EXISTS ( SELECT 1 FROM issue_comments ic WHERE ic.repo = i.repo AND ic.issue_number = i.number AND ic.author IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]') AND ic.created_at > COALESCE( (SELECT MAX(ic2.created_at) FROM issue_comments ic2 WHERE ic2.repo = i.repo AND ic2.issue_number = i.number AND ic2.author NOT IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]')), i.created_at))", + "queryType": "table", + "rawQueryText": "SELECT COUNT(DISTINCT i.id) as value FROM issues i WHERE i.state = 'open' AND i.repo IN (${repo:singlequote}) AND i.author NOT IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]') AND NOT EXISTS ( SELECT 1 FROM issue_comments ic WHERE ic.repo = i.repo AND ic.issue_number = i.number AND ic.author IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]') AND ic.created_at > COALESCE( (SELECT MAX(ic2.created_at) FROM issue_comments ic2 WHERE ic2.repo = i.repo AND ic2.issue_number = i.number AND ic2.author NOT IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]')), i.created_at))", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + } + }, + { + "id": 327, + "type": "stat", + "title": "PRs Without Reviews", + "description": "Open PRs that have received zero reviews.", + "gridPos": { + "x": 12, + "y": 70, + "h": 4, + "w": 12 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed", + "fixedColor": "yellow" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ], + "fields": "" + }, + "orientation": "auto", + "textMode": "auto", + "wideLayout": true, + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "showPercentChange": false + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT COUNT(*) as value FROM pull_requests p WHERE p.state = 'open' AND p.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND NOT EXISTS ( SELECT 1 FROM pr_reviews r WHERE r.repo = p.repo AND r.pr_number = p.number)", + "queryType": "table", + "rawQueryText": "SELECT COUNT(*) as value FROM pull_requests p WHERE p.state = 'open' AND p.repo IN (${repo:singlequote}) AND NOT EXISTS ( SELECT 1 FROM pr_reviews r WHERE r.repo = p.repo AND r.pr_number = p.number)", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + } + }, + { + "id": 328, + "type": "bargauge", + "title": "Issues Awaiting Response by Repo", + "description": "Open issues awaiting maintainer response, by repository.", + "gridPos": { + "x": 0, + "y": 74, + "h": 6, + "w": 12 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "values": true, + "calcs": [], + "fields": "" + }, + "orientation": "horizontal", + "displayMode": "gradient", + "showUnfilled": true, + "valueMode": "color", + "sizing": "auto", + "minVizWidth": 8, + "minVizHeight": 16, + "maxVizHeight": 300, + "namePlacement": "auto", + "legend": { + "showLegend": false, + "displayMode": "hidden", + "placement": "bottom" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT i.repo, COUNT(DISTINCT i.id) as count FROM issues i WHERE i.state = 'open' AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND i.author NOT IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]') AND NOT EXISTS ( SELECT 1 FROM issue_comments ic WHERE ic.repo = i.repo AND ic.issue_number = i.number AND ic.author IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]') AND ic.created_at > COALESCE( (SELECT MAX(ic2.created_at) FROM issue_comments ic2 WHERE ic2.repo = i.repo AND ic2.issue_number = i.number AND ic2.author NOT IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]')), i.created_at)) GROUP BY i.repo ORDER BY count DESC", + "queryType": "table", + "rawQueryText": "SELECT i.repo, COUNT(DISTINCT i.id) as count FROM issues i WHERE i.state = 'open' AND i.repo IN (${repo:singlequote}) AND i.author NOT IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]') AND NOT EXISTS ( SELECT 1 FROM issue_comments ic WHERE ic.repo = i.repo AND ic.issue_number = i.number AND ic.author IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]') AND ic.created_at > COALESCE( (SELECT MAX(ic2.created_at) FROM issue_comments ic2 WHERE ic2.repo = i.repo AND ic2.issue_number = i.number AND ic2.author NOT IN ('afarntrog','lizradway','JackYPCOnline','chaynabors','dbschmigelski','zastrowm','mehtarac','mkmeral','Unshure','pgrayy','poshinchen','strands-agent','dependabot[bot]','github-actions[bot]')), i.created_at)) GROUP BY i.repo ORDER BY count DESC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + } + }, + { + "id": 329, + "type": "bargauge", + "title": "PRs Without Reviews by Repo", + "description": "Open PRs with no reviews, by repository.", + "gridPos": { + "x": 12, + "y": 74, + "h": 6, + "w": 12 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "values": true, + "calcs": [], + "fields": "" + }, + "orientation": "horizontal", + "displayMode": "gradient", + "showUnfilled": true, + "valueMode": "color", + "sizing": "auto", + "minVizWidth": 8, + "minVizHeight": 16, + "maxVizHeight": 300, + "namePlacement": "auto", + "legend": { + "showLegend": false, + "displayMode": "hidden", + "placement": "bottom" + } + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT p.repo, COUNT(*) as count FROM pull_requests p WHERE p.state = 'open' AND p.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') AND NOT EXISTS ( SELECT 1 FROM pr_reviews r WHERE r.repo = p.repo AND r.pr_number = p.number) GROUP BY p.repo ORDER BY count DESC", + "queryType": "table", + "rawQueryText": "SELECT p.repo, COUNT(*) as count FROM pull_requests p WHERE p.state = 'open' AND p.repo IN (${repo:singlequote}) AND NOT EXISTS ( SELECT 1 FROM pr_reviews r WHERE r.repo = p.repo AND r.pr_number = p.number) GROUP BY p.repo ORDER BY count DESC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + } + }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 58 + "y": 80 }, "id": 101, "panels": [], @@ -563,7 +1245,7 @@ "h": 1, "w": 24, "x": 0, - "y": 75 + "y": 97 }, "id": 102, "panels": [], @@ -576,7 +1258,7 @@ "h": 1, "w": 24, "x": 0, - "y": 92 + "y": 114 }, "id": 103, "panels": [], @@ -1475,7 +2157,7 @@ "h": 8, "w": 12, "x": 0, - "y": 93 + "y": 115 }, "id": 12, "options": { @@ -2407,7 +3089,7 @@ "h": 8, "w": 12, "x": 12, - "y": 93 + "y": 115 }, "id": 10, "options": { @@ -2677,7 +3359,7 @@ "h": 8, "w": 12, "x": 0, - "y": 101 + "y": 123 }, "id": 18, "options": { @@ -3623,7 +4305,7 @@ "h": 8, "w": 12, "x": 12, - "y": 101 + "y": 123 }, "id": 9, "options": { @@ -3891,7 +4573,7 @@ "h": 8, "w": 12, "x": 12, - "y": 67 + "y": 89 }, "id": 19, "options": { @@ -4175,7 +4857,7 @@ "h": 8, "w": 12, "x": 0, - "y": 76 + "y": 98 }, "id": 13, "options": { @@ -4470,7 +5152,7 @@ "h": 8, "w": 12, "x": 0, - "y": 84 + "y": 106 }, "id": 14, "options": { @@ -4746,7 +5428,7 @@ "h": 8, "w": 12, "x": 12, - "y": 76 + "y": 98 }, "id": 15, "options": { @@ -5041,7 +5723,7 @@ "h": 8, "w": 12, "x": 12, - "y": 84 + "y": 106 }, "id": 16, "options": { @@ -5976,7 +6658,7 @@ "h": 8, "w": 12, "x": 0, - "y": 67 + "y": 89 }, "id": 7, "options": { @@ -6446,7 +7128,7 @@ "h": 8, "w": 12, "x": 0, - "y": 59 + "y": 81 }, "id": 17, "options": { @@ -6914,7 +7596,7 @@ "h": 8, "w": 12, "x": 12, - "y": 59 + "y": 81 }, "id": 20, "options": { @@ -6987,7 +7669,7 @@ "h": 1, "w": 24, "x": 0, - "y": 109 + "y": 131 }, "id": 104, "panels": [], @@ -7086,7 +7768,7 @@ "h": 8, "w": 12, "x": 0, - "y": 110 + "y": 132 }, "id": 21, "options": { @@ -7199,7 +7881,7 @@ "h": 8, "w": 12, "x": 12, - "y": 110 + "y": 132 }, "id": 22, "options": { @@ -7337,7 +8019,7 @@ "h": 10, "w": 12, "x": 0, - "y": 118 + "y": 140 }, "id": 23, "options": { @@ -7422,7 +8104,7 @@ "h": 10, "w": 12, "x": 12, - "y": 118 + "y": 140 }, "id": 24, "options": { @@ -7524,7 +8206,7 @@ "h": 8, "w": 24, "x": 0, - "y": 128 + "y": 150 }, "id": 25, "options": { @@ -7571,7 +8253,7 @@ "h": 1, "w": 24, "x": 0, - "y": 6 + "y": 28 }, "id": 300, "panels": [], @@ -7607,7 +8289,7 @@ "h": 4, "w": 4, "x": 0, - "y": 7 + "y": 29 }, "id": 301, "options": { @@ -7665,7 +8347,7 @@ "h": 4, "w": 4, "x": 4, - "y": 7 + "y": 29 }, "id": 302, "options": { @@ -7723,7 +8405,7 @@ "h": 4, "w": 4, "x": 8, - "y": 7 + "y": 29 }, "id": 303, "options": { @@ -7781,7 +8463,7 @@ "h": 4, "w": 4, "x": 12, - "y": 7 + "y": 29 }, "id": 304, "options": { @@ -7868,7 +8550,7 @@ "h": 8, "w": 12, "x": 0, - "y": 11 + "y": 33 }, "id": 305, "options": { @@ -7966,7 +8648,7 @@ "h": 8, "w": 12, "x": 12, - "y": 11 + "y": 33 }, "id": 306, "options": { @@ -8063,7 +8745,7 @@ "h": 8, "w": 6, "x": 0, - "y": 19 + "y": 41 }, "id": 307, "options": { @@ -8164,7 +8846,7 @@ "h": 8, "w": 10, "x": 6, - "y": 19 + "y": 41 }, "id": 308, "options": { @@ -8257,7 +8939,7 @@ "h": 8, "w": 8, "x": 16, - "y": 19 + "y": 41 }, "id": 309, "options": { @@ -8325,7 +9007,7 @@ "h": 6, "w": 12, "x": 12, - "y": 28 + "y": 50 }, "id": 310, "options": { @@ -8389,7 +9071,7 @@ "h": 6, "w": 12, "x": 0, - "y": 28 + "y": 50 }, "id": 311, "options": { @@ -8605,7 +9287,7 @@ "h": 8, "w": 12, "x": 12, - "y": 34 + "y": 56 }, "id": 312, "options": { @@ -8801,7 +9483,7 @@ "h": 8, "w": 12, "x": 0, - "y": 34 + "y": 56 }, "id": 313, "options": { @@ -9737,7 +10419,7 @@ "h": 8, "w": 12, "x": 12, - "y": 42 + "y": 64 }, "id": 314, "options": { @@ -10661,7 +11343,7 @@ "h": 8, "w": 12, "x": 12, - "y": 50 + "y": 72 }, "id": 315, "options": { @@ -11595,7 +12277,7 @@ "h": 8, "w": 12, "x": 0, - "y": 42 + "y": 64 }, "id": 316, "options": { @@ -12519,7 +13201,7 @@ "h": 8, "w": 12, "x": 0, - "y": 50 + "y": 72 }, "id": 317, "options": { @@ -12607,4 +13289,4 @@ "title": "Overview", "uid": "adj9pgt", "version": 10 -} +} \ No newline at end of file diff --git a/community-dashboard/strands-metrics/src/client.rs b/community-dashboard/strands-metrics/src/client.rs index fe39d58..96af1d9 100644 --- a/community-dashboard/strands-metrics/src/client.rs +++ b/community-dashboard/strands-metrics/src/client.rs @@ -53,6 +53,10 @@ impl<'a> GitHubClient<'a> { self.pb.set_message(format!("Syncing {}", repo.name)); self.sync_repo(org, &repo).await?; } + + // Sync GitHub Project V2 items (project #4 = Strands Agents board) + self.sync_project_items(org, 4).await?; + Ok(()) } @@ -716,6 +720,157 @@ impl<'a> GitHubClient<'a> { Ok(()) } + /// Sync GitHub Project V2 items (org-level, not per-repo). + /// Fetches priority and status fields from the specified project number. + pub async fn sync_project_items(&self, org: &str, project_number: i32) -> Result<()> { + self.pb.set_message(format!("Syncing project #{} items...", project_number)); + + // Clear existing project items and re-sync fully each time. + // Project items don't have a reliable "updated since" filter via GraphQL. + self.db.execute("DELETE FROM project_items", [])?; + + let mut cursor: Option = None; + let mut total = 0u64; + + loop { + self.check_limits().await?; + + let after_clause = cursor + .as_ref() + .map(|c| format!(r#", after: "{}""#, c)) + .unwrap_or_default(); + + let query = format!( + r#"query {{ + organization(login: "{}") {{ + projectV2(number: {}) {{ + items(first: 100{}) {{ + nodes {{ + id + updatedAt + content {{ + ... on Issue {{ + number + repository {{ name }} + }} + }} + priority: fieldValueByName(name: "Priority") {{ + ... on ProjectV2ItemFieldSingleSelectValue {{ + name + }} + }} + status: fieldValueByName(name: "Status") {{ + ... on ProjectV2ItemFieldSingleSelectValue {{ + name + }} + }} + }} + pageInfo {{ + hasNextPage + endCursor + }} + }} + }} + }} +}}"#, + org, project_number, after_clause + ); + + let response: Value = self + .gh + .graphql(&serde_json::json!({ "query": query })) + .await?; + + // Check for GraphQL errors + if let Some(errors) = response.get("errors") { + let err_msg = errors.to_string(); + if err_msg.contains("Could not resolve") || err_msg.contains("insufficient") { + tracing::error!( + "Cannot access project #{} — ensure GITHUB_TOKEN has project read scope. Error: {}", + project_number, err_msg + ); + return Ok(()); + } + tracing::warn!("GraphQL errors syncing project items: {}", err_msg); + } + + let items = match response.pointer("/data/organization/projectV2/items") { + Some(i) => i, + None => { + tracing::error!( + "No project data returned for project #{}. Ensure GITHUB_TOKEN has 'read:project' scope. Response: {}", + project_number, + serde_json::to_string_pretty(&response).unwrap_or_default() + ); + return Ok(()); + } + }; + + let nodes = items + .get("nodes") + .and_then(|n| n.as_array()) + .cloned() + .unwrap_or_default(); + + for node in &nodes { + let node_id = node.get("id").and_then(|v| v.as_str()).unwrap_or(""); + let updated_at = node + .get("updatedAt") + .and_then(|v| v.as_str()) + .unwrap_or(""); + + // content can be null for draft items + let content = match node.get("content") { + Some(c) if !c.is_null() => c, + _ => continue, + }; + + let issue_number = match content.get("number").and_then(|n| n.as_i64()) { + Some(n) => n, + None => continue, // Not an issue (could be a PR or draft) + }; + + let repo = content + .pointer("/repository/name") + .and_then(|v| v.as_str()) + .unwrap_or(""); + + if repo.is_empty() { + continue; + } + + let priority = node.pointer("/priority/name").and_then(|v| v.as_str()); + let status = node.pointer("/status/name").and_then(|v| v.as_str()); + + self.db.execute( + "INSERT OR REPLACE INTO project_items (node_id, repo, issue_number, priority, status, updated_at) + VALUES (?1, ?2, ?3, ?4, ?5, ?6)", + params![node_id, repo, issue_number, priority, status, updated_at], + )?; + total += 1; + } + + let page_info = items.get("pageInfo"); + let has_next = page_info + .and_then(|p| p.get("hasNextPage")) + .and_then(|v| v.as_bool()) + .unwrap_or(false); + + if has_next { + cursor = page_info + .and_then(|p| p.get("endCursor")) + .and_then(|v| v.as_str()) + .map(String::from); + } else { + break; + } + } + + self.pb + .set_message(format!("Synced {} project items", total)); + Ok(()) + } + fn is_missing_resource(err: &octocrab::Error) -> bool { match err { octocrab::Error::GitHub { source, .. } => { diff --git a/community-dashboard/strands-metrics/src/db.rs b/community-dashboard/strands-metrics/src/db.rs index dc711aa..b9e7320 100644 --- a/community-dashboard/strands-metrics/src/db.rs +++ b/community-dashboard/strands-metrics/src/db.rs @@ -25,7 +25,7 @@ pub fn init_db>(path: P) -> Result { updated_at TEXT NOT NULL, merged_at TEXT, closed_at TEXT, - deleted_at TEXT, + deleted_at TEXT, data TEXT NOT NULL )", [], @@ -124,6 +124,18 @@ pub fn init_db>(path: P) -> Result { [], )?; + conn.execute( + "CREATE TABLE IF NOT EXISTS project_items ( + node_id TEXT PRIMARY KEY, + repo TEXT NOT NULL, + issue_number INTEGER NOT NULL, + priority TEXT, + status TEXT, + updated_at TEXT NOT NULL + )", + [], + )?; + conn.execute( "CREATE TABLE IF NOT EXISTS daily_metrics ( date TEXT NOT NULL, @@ -161,35 +173,15 @@ pub fn init_db>(path: P) -> Result { [], )?; - conn.execute( - "CREATE INDEX IF NOT EXISTS idx_pr_repo_updated ON pull_requests(repo, updated_at)", - [], - )?; - conn.execute( - "CREATE INDEX IF NOT EXISTS idx_issues_repo_updated ON issues(repo, updated_at)", - [], - )?; - conn.execute( - "CREATE INDEX IF NOT EXISTS idx_comments_repo_issue ON issue_comments(repo, issue_number)", - [], - )?; - conn.execute( - "CREATE INDEX IF NOT EXISTS idx_reviews_repo_pr ON pr_reviews(repo, pr_number)", - [], - )?; + conn.execute("CREATE INDEX IF NOT EXISTS idx_pr_repo_updated ON pull_requests(repo, updated_at)", [])?; + conn.execute("CREATE INDEX IF NOT EXISTS idx_issues_repo_updated ON issues(repo, updated_at)", [])?; + conn.execute("CREATE INDEX IF NOT EXISTS idx_comments_repo_issue ON issue_comments(repo, issue_number)", [])?; + conn.execute("CREATE INDEX IF NOT EXISTS idx_reviews_repo_pr ON pr_reviews(repo, pr_number)", [])?; conn.execute("CREATE INDEX IF NOT EXISTS idx_review_comments_repo_pr ON pr_review_comments(repo, pr_number)", [])?; - conn.execute( - "CREATE INDEX IF NOT EXISTS idx_stars_repo_date ON stargazers(repo, starred_at)", - [], - )?; - conn.execute( - "CREATE INDEX IF NOT EXISTS idx_commits_repo_date ON commits(repo, date)", - [], - )?; - conn.execute( - "CREATE INDEX IF NOT EXISTS idx_workflows_repo_date ON workflow_runs(repo, created_at)", - [], - )?; + conn.execute("CREATE INDEX IF NOT EXISTS idx_stars_repo_date ON stargazers(repo, starred_at)", [])?; + conn.execute("CREATE INDEX IF NOT EXISTS idx_commits_repo_date ON commits(repo, date)", [])?; + conn.execute("CREATE INDEX IF NOT EXISTS idx_workflows_repo_date ON workflow_runs(repo, created_at)", [])?; + conn.execute("CREATE INDEX IF NOT EXISTS idx_project_items_repo ON project_items(repo, issue_number)", [])?; // Package download tracking conn.execute( @@ -204,21 +196,11 @@ pub fn init_db>(path: P) -> Result { [], )?; - conn.execute( - "CREATE INDEX IF NOT EXISTS idx_downloads_package_date ON package_downloads(package, date)", - [], - )?; + conn.execute("CREATE INDEX IF NOT EXISTS idx_downloads_package_date ON package_downloads(package, date)", [])?; // ── Migrations for existing databases ────────────────────────────── - // ALTER TABLE is idempotent-safe: we ignore "duplicate column" errors. - let _ = conn.execute( - "ALTER TABLE daily_metrics ADD COLUMN weekly_community_contributors INTEGER DEFAULT 0", - [], - ); - let _ = conn.execute( - "ALTER TABLE daily_metrics ADD COLUMN cumulative_community_contributors INTEGER DEFAULT 0", - [], - ); + let _ = conn.execute("ALTER TABLE daily_metrics ADD COLUMN weekly_community_contributors INTEGER DEFAULT 0", []); + let _ = conn.execute("ALTER TABLE daily_metrics ADD COLUMN cumulative_community_contributors INTEGER DEFAULT 0", []); Ok(conn) } From 03dbc4c70d6466ce2206b32e98dd2dba10fcbdf0 Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Fri, 27 Feb 2026 12:06:53 -0500 Subject: [PATCH 16/22] feat: add triage tracking, backfill, and GraphQL rate limiting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add triaged_at column to project_items table (schema + migration) - Track NULL→non-NULL priority transitions as triage events during sync - Add backfill-triage CLI command using timeline API - Add graphql_with_retry() with exponential backoff for rate limits - Check both REST and GraphQL rate limit buckets - Make sync_org resilient to per-repo errors --- .../dashboards/general/health.json | 3819 ++--------------- .../strands-metrics/src/client.rs | 291 +- community-dashboard/strands-metrics/src/db.rs | 4 +- .../strands-metrics/src/main.rs | 14 + 4 files changed, 754 insertions(+), 3374 deletions(-) diff --git a/community-dashboard/provisioning/dashboards/general/health.json b/community-dashboard/provisioning/dashboards/general/health.json index fec3727..d5f13fd 100644 --- a/community-dashboard/provisioning/dashboards/general/health.json +++ b/community-dashboard/provisioning/dashboards/general/health.json @@ -566,7 +566,7 @@ "x": 0, "y": 59, "h": 4, - "w": 6 + "w": 4 }, "fieldConfig": { "defaults": { @@ -627,10 +627,10 @@ "title": "Sev2 Open", "description": "Open issues with Sev2 priority.", "gridPos": { - "x": 6, + "x": 4, "y": 59, "h": 4, - "w": 6 + "w": 4 }, "fieldConfig": { "defaults": { @@ -691,10 +691,10 @@ "title": "On-Call Open", "description": "Open issues with On-Call priority.", "gridPos": { - "x": 12, + "x": 8, "y": 59, "h": 4, - "w": 6 + "w": 4 }, "fieldConfig": { "defaults": { @@ -755,10 +755,10 @@ "title": "High Open", "description": "Open issues with High priority.", "gridPos": { - "x": 18, + "x": 12, "y": 59, "h": 4, - "w": 6 + "w": 4 }, "fieldConfig": { "defaults": { @@ -955,7 +955,7 @@ "title": "Responsiveness", "gridPos": { "x": 0, - "y": 69, + "y": 85, "h": 1, "w": 24 }, @@ -969,7 +969,7 @@ "description": "Open issues from non-maintainers where the last comment is not from a team member.", "gridPos": { "x": 0, - "y": 70, + "y": 86, "h": 4, "w": 12 }, @@ -1033,7 +1033,7 @@ "description": "Open PRs that have received zero reviews.", "gridPos": { "x": 12, - "y": 70, + "y": 86, "h": 4, "w": 12 }, @@ -1097,7 +1097,7 @@ "description": "Open issues awaiting maintainer response, by repository.", "gridPos": { "x": 0, - "y": 74, + "y": 90, "h": 6, "w": 12 }, @@ -1165,7 +1165,7 @@ "description": "Open PRs with no reviews, by repository.", "gridPos": { "x": 12, - "y": 74, + "y": 90, "h": 6, "w": 12 }, @@ -1232,7 +1232,7 @@ "h": 1, "w": 24, "x": 0, - "y": 80 + "y": 96 }, "id": 101, "panels": [], @@ -1245,7 +1245,7 @@ "h": 1, "w": 24, "x": 0, - "y": 97 + "y": 113 }, "id": 102, "panels": [], @@ -1258,7 +1258,7 @@ "h": 1, "w": 24, "x": 0, - "y": 114 + "y": 130 }, "id": 103, "panels": [], @@ -2157,7 +2157,7 @@ "h": 8, "w": 12, "x": 0, - "y": 115 + "y": 131 }, "id": 12, "options": { @@ -3089,7 +3089,7 @@ "h": 8, "w": 12, "x": 12, - "y": 115 + "y": 131 }, "id": 10, "options": { @@ -3359,7 +3359,7 @@ "h": 8, "w": 12, "x": 0, - "y": 123 + "y": 139 }, "id": 18, "options": { @@ -4305,7 +4305,7 @@ "h": 8, "w": 12, "x": 12, - "y": 123 + "y": 139 }, "id": 9, "options": { @@ -4573,7 +4573,7 @@ "h": 8, "w": 12, "x": 12, - "y": 89 + "y": 105 }, "id": 19, "options": { @@ -4857,7 +4857,7 @@ "h": 8, "w": 12, "x": 0, - "y": 98 + "y": 114 }, "id": 13, "options": { @@ -5152,7 +5152,7 @@ "h": 8, "w": 12, "x": 0, - "y": 106 + "y": 122 }, "id": 14, "options": { @@ -5428,7 +5428,7 @@ "h": 8, "w": 12, "x": 12, - "y": 98 + "y": 114 }, "id": 15, "options": { @@ -5723,7 +5723,7 @@ "h": 8, "w": 12, "x": 12, - "y": 106 + "y": 122 }, "id": 16, "options": { @@ -6658,7 +6658,7 @@ "h": 8, "w": 12, "x": 0, - "y": 89 + "y": 105 }, "id": 7, "options": { @@ -7128,7 +7128,7 @@ "h": 8, "w": 12, "x": 0, - "y": 81 + "y": 97 }, "id": 17, "options": { @@ -7596,7 +7596,7 @@ "h": 8, "w": 12, "x": 12, - "y": 81 + "y": 97 }, "id": 20, "options": { @@ -7669,7 +7669,7 @@ "h": 1, "w": 24, "x": 0, - "y": 131 + "y": 147 }, "id": 104, "panels": [], @@ -7768,7 +7768,7 @@ "h": 8, "w": 12, "x": 0, - "y": 132 + "y": 148 }, "id": 21, "options": { @@ -7881,7 +7881,7 @@ "h": 8, "w": 12, "x": 12, - "y": 132 + "y": 148 }, "id": 22, "options": { @@ -8019,7 +8019,7 @@ "h": 10, "w": 12, "x": 0, - "y": 140 + "y": 156 }, "id": 23, "options": { @@ -8104,7 +8104,7 @@ "h": 10, "w": 12, "x": 12, - "y": 140 + "y": 156 }, "id": 24, "options": { @@ -8206,7 +8206,7 @@ "h": 8, "w": 24, "x": 0, - "y": 150 + "y": 166 }, "id": 25, "options": { @@ -9533,11 +9533,165 @@ "type": "timeseries" }, { + "id": 330, + "type": "stat", + "title": "Avg Time to Triage", + "description": "Average hours from issue creation to triage (priority assigned).", + "gridPos": { + "x": 16, + "y": 59, + "w": 4, + "h": 4 + }, + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT ROUND(AVG((julianday(pi.triaged_at) - julianday(i.created_at)) * 24), 1) as value\nFROM project_items pi\nJOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\nWHERE pi.triaged_at IS NOT NULL AND pi.priority IS NOT NULL\nAND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')", + "queryType": "table", + "rawQueryText": "SELECT ROUND(AVG((julianday(pi.triaged_at) - julianday(i.created_at)) * 24), 1) as value\nFROM project_items pi\nJOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\nWHERE pi.triaged_at IS NOT NULL AND pi.priority IS NOT NULL\nAND i.repo IN (${repo:singlequote})", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "fieldConfig": { + "defaults": { + "unit": "h", + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 24 + }, + { + "color": "red", + "value": 72 + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "orientation": "auto", + "textMode": "auto", + "wideLayout": true, + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "showPercentChange": false + } + }, + { + "id": 331, + "type": "stat", + "title": "P90 Time to Triage", + "description": "90th percentile hours from issue creation to triage. Excludes items where triaged_at == created_at (fallback timestamps).", + "gridPos": { + "x": 20, + "y": 59, + "w": 4, + "h": 4 + }, + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "pluginVersion": "12.3.1", + "targets": [ + { + "queryText": "SELECT ROUND(hours, 1) as value FROM (\n SELECT (julianday(pi.triaged_at) - julianday(i.created_at)) * 24 as hours\n FROM project_items pi\n JOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\n WHERE pi.triaged_at IS NOT NULL AND pi.priority IS NOT NULL\n AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND pi.triaged_at != i.created_at\n ORDER BY hours ASC\n LIMIT 1\n OFFSET (SELECT CAST(COUNT(*) * 0.9 AS INTEGER)\n FROM project_items pi2\n JOIN issues i2 ON pi2.repo = i2.repo AND pi2.issue_number = i2.number\n WHERE pi2.triaged_at IS NOT NULL AND pi2.priority IS NOT NULL\n AND i2.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND pi2.triaged_at != i2.created_at)\n)", + "queryType": "table", + "rawQueryText": "SELECT ROUND(hours, 1) as value FROM (\n SELECT (julianday(pi.triaged_at) - julianday(i.created_at)) * 24 as hours\n FROM project_items pi\n JOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\n WHERE pi.triaged_at IS NOT NULL AND pi.priority IS NOT NULL\n AND i.repo IN (${repo:singlequote})\n AND pi.triaged_at != i.created_at\n ORDER BY hours ASC\n LIMIT 1\n OFFSET (SELECT CAST(COUNT(*) * 0.9 AS INTEGER)\n FROM project_items pi2\n JOIN issues i2 ON pi2.repo = i2.repo AND pi2.issue_number = i2.number\n WHERE pi2.triaged_at IS NOT NULL AND pi2.priority IS NOT NULL\n AND i2.repo IN (${repo:singlequote})\n AND pi2.triaged_at != i2.created_at)\n)", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "fieldConfig": { + "defaults": { + "unit": "h", + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 48 + }, + { + "color": "red", + "value": 168 + } + ] + } + }, + "overrides": [] + }, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "orientation": "auto", + "textMode": "auto", + "wideLayout": true, + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "showPercentChange": false + } + }, + { + "id": 332, + "type": "timeseries", + "title": "Triage Velocity (Weekly)", + "description": "Issues added to project and triaged per week with net delta.", "datasource": { "type": "frser-sqlite-datasource", "uid": "P2289B60D79A89B0C" }, - "description": "Weekly PRs opened per repository, stacked.", + "pluginVersion": "12.3.1", + "gridPos": { + "x": 0, + "y": 69, + "w": 24, + "h": 8 + }, "fieldConfig": { "defaults": { "color": { @@ -9551,8 +9705,8 @@ "axisPlacement": "auto", "barAlignment": 0, "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 10, + "drawStyle": "bars", + "fillOpacity": 30, "gradientMode": "none", "hideFrom": { "legend": false, @@ -9561,7 +9715,7 @@ }, "insertNulls": false, "lineInterpolation": "linear", - "lineWidth": 2, + "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" @@ -9591,13 +9745,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python" + "options": "Added" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "light-blue", "mode": "fixed" } } @@ -9606,13 +9760,13 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (Internal)" + "options": "Triaged" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "semi-dark-green", "mode": "fixed" } } @@ -9621,3260 +9775,170 @@ { "matcher": { "id": "byName", - "options": "value sdk-python (External)" + "options": "Delta" }, "properties": [ { "id": "color", "value": { - "fixedColor": "blue", + "fixedColor": "white", "mode": "fixed" } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ + }, { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ + "id": "custom.drawStyle", + "value": "line" + }, { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ + "id": "custom.fillOpacity", + "value": 0 + }, { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ + "id": "custom.lineWidth", + "value": 2 + }, { - "id": "color", + "id": "custom.lineStyle", "value": { - "fixedColor": "green", - "mode": "fixed" + "fill": "dash", + "dash": [ + 10, + 5 + ] } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ + }, { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 64 - }, - "id": 314, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "multi", - "sort": "desc" - } - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(prs_opened) as value\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(prs_opened) as value\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "PRs Opened by Repo (Weekly)", - "type": "timeseries", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ] - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "Weekly PRs merged + rejected per repository, stacked.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 72 - }, - "id": 315, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "multi", - "sort": "desc" - } - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(prs_merged) as value\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(prs_merged) as value\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - }, - { - "queryText": "SELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(closed_at), 'weekday 0', '-6 days'), repo\nORDER BY time ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date(date(closed_at), 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n COUNT(*) as value\nFROM pull_requests\nWHERE state = 'closed' \n AND merged_at IS NULL \n AND repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date(closed_at)) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date(closed_at)) as INTEGER) <= $__to / 1000\nGROUP BY date(date(closed_at), 'weekday 0', '-6 days'), repo\nORDER BY time ASC", - "refId": "B", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "PRs Closed by Repo (Weekly)", - "type": "timeseries", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ] - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "Weekly issues opened per repository, stacked.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value mcp-server (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value .github (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value devtools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "light-green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 64 - }, - "id": 316, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "multi", - "sort": "desc" - } - }, - "targets": [ - { - "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(issues_opened) as value\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", - "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(issues_opened) as value\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", - "refId": "A", - "timeColumns": [ - "time", - "ts" - ] - } - ], - "title": "Issues Opened by Repo (Weekly)", - "type": "timeseries", - "transformations": [ - { - "id": "prepareTimeSeries", - "options": { - "format": "multi" - } - } - ] - }, - { - "datasource": { - "type": "frser-sqlite-datasource", - "uid": "P2289B60D79A89B0C" - }, - "description": "Weekly issues closed per repository, stacked.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "value sdk-python" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-python (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value sdk-typescript (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value tools (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value docs (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-builder (Resolution Time)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Internal)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (External)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (First Response)" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } + "id": "custom.showPoints", + "value": "always" + }, + { + "id": "custom.pointSize", + "value": 6 } ] + } + ] + }, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(i.created_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n COUNT(*) as \"Added\"\nFROM project_items pi\nJOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\nWHERE i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', i.created_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', i.created_at) as INTEGER) <= $__to / 1000\nGROUP BY date(i.created_at, 'weekday 0', '-6 days')\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(i.created_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n COUNT(*) as \"Added\"\nFROM project_items pi\nJOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\nWHERE i.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', i.created_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', i.created_at) as INTEGER) <= $__to / 1000\nGROUP BY date(i.created_at, 'weekday 0', '-6 days')\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT \n CAST(strftime('%s', date(pi.triaged_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n COUNT(*) as \"Triaged\"\nFROM project_items pi\nJOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\nWHERE pi.triaged_at IS NOT NULL AND pi.priority IS NOT NULL\n AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) <= $__to / 1000\nGROUP BY date(pi.triaged_at, 'weekday 0', '-6 days')\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(pi.triaged_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n COUNT(*) as \"Triaged\"\nFROM project_items pi\nJOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\nWHERE pi.triaged_at IS NOT NULL AND pi.priority IS NOT NULL\n AND i.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) <= $__to / 1000\nGROUP BY date(pi.triaged_at, 'weekday 0', '-6 days')\nORDER BY time ASC", + "refId": "B", + "timeColumns": [ + "time", + "ts" + ] + }, + { + "queryText": "SELECT \n a.time,\n a.added - COALESCE(t.triaged, 0) as \"Delta\"\nFROM (\n SELECT CAST(strftime('%s', date(i.created_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n COUNT(*) as added\n FROM project_items pi\n JOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\n WHERE i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', i.created_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', i.created_at) as INTEGER) <= $__to / 1000\n GROUP BY date(i.created_at, 'weekday 0', '-6 days')\n) a\nLEFT JOIN (\n SELECT CAST(strftime('%s', date(pi.triaged_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n COUNT(*) as triaged\n FROM project_items pi\n JOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\n WHERE pi.triaged_at IS NOT NULL AND pi.priority IS NOT NULL\n AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) <= $__to / 1000\n GROUP BY date(pi.triaged_at, 'weekday 0', '-6 days')\n) t ON a.time = t.time\nORDER BY a.time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n a.time,\n a.added - COALESCE(t.triaged, 0) as \"Delta\"\nFROM (\n SELECT CAST(strftime('%s', date(i.created_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n COUNT(*) as added\n FROM project_items pi\n JOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\n WHERE i.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', i.created_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', i.created_at) as INTEGER) <= $__to / 1000\n GROUP BY date(i.created_at, 'weekday 0', '-6 days')\n) a\nLEFT JOIN (\n SELECT CAST(strftime('%s', date(pi.triaged_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n COUNT(*) as triaged\n FROM project_items pi\n JOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\n WHERE pi.triaged_at IS NOT NULL AND pi.priority IS NOT NULL\n AND i.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) <= $__to / 1000\n GROUP BY date(pi.triaged_at, 'weekday 0', '-6 days')\n) t ON a.time = t.time\nORDER BY a.time ASC", + "refId": "C", + "timeColumns": [ + "time", + "ts" + ] + } + ] + }, + { + "id": 333, + "type": "timeseries", + "title": "Issues Added to Project by Repo (Weekly)", + "description": "Weekly issues added to project, broken down by repository.", + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "pluginVersion": "12.3.1", + "gridPos": { + "x": 0, + "y": 77, + "w": 12, + "h": 8 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" }, - { - "matcher": { - "id": "byName", - "options": "value agent-sop (Resolution Time)" + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples" + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value samples (Internal)" + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } - } - ] + "thresholdsStyle": { + "mode": "off" + } }, - { - "matcher": { - "id": "byName", - "options": "value samples (External)" - }, - "properties": [ + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ { - "id": "color", - "value": { - "fixedColor": "purple", - "mode": "fixed" - } + "color": "green", + "value": null } ] - }, + } + }, + "overrides": [ { "matcher": { "id": "byName", - "options": "value samples (First Response)" + "options": "sdk-python" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "#6C47FF", "mode": "fixed" } } @@ -12883,13 +9947,13 @@ { "matcher": { "id": "byName", - "options": "value samples (Resolution Time)" + "options": "sdk-typescript" }, "properties": [ { "id": "color", "value": { - "fixedColor": "purple", + "fixedColor": "#2196F3", "mode": "fixed" } } @@ -12898,13 +9962,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server" + "options": "tools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "#FF9800", "mode": "fixed" } } @@ -12913,13 +9977,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server (Internal)" + "options": "docs" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "#4CAF50", "mode": "fixed" } } @@ -12928,13 +9992,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server (External)" + "options": "evals" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "#E91E63", "mode": "fixed" } } @@ -12943,13 +10007,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server (First Response)" + "options": "samples" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "#00BCD4", "mode": "fixed" } } @@ -12958,13 +10022,13 @@ { "matcher": { "id": "byName", - "options": "value mcp-server (Resolution Time)" + "options": "mcp-server" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-orange", + "fixedColor": "#9C27B0", "mode": "fixed" } } @@ -12973,13 +10037,13 @@ { "matcher": { "id": "byName", - "options": "value evals" + "options": "agent-builder" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-green", + "fixedColor": "#FF5722", "mode": "fixed" } } @@ -12988,88 +10052,128 @@ { "matcher": { "id": "byName", - "options": "value evals (Internal)" + "options": "strandsagents.com" }, "properties": [ { "id": "color", "value": { - "fixedColor": "dark-green", + "fixedColor": "#607D8B", "mode": "fixed" } } ] + } + ] + }, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "queryText": "SELECT \n CAST(strftime('%s', date(i.created_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n pi.repo as metric,\n COUNT(*) as value\nFROM project_items pi\nJOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\nWHERE i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', i.created_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', i.created_at) as INTEGER) <= $__to / 1000\nGROUP BY date(i.created_at, 'weekday 0', '-6 days'), pi.repo\nORDER BY time ASC", + "queryType": "table", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(i.created_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n pi.repo as metric,\n COUNT(*) as value\nFROM project_items pi\nJOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\nWHERE i.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', i.created_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', i.created_at) as INTEGER) <= $__to / 1000\nGROUP BY date(i.created_at, 'weekday 0', '-6 days'), pi.repo\nORDER BY time ASC", + "refId": "A", + "timeColumns": [ + "time", + "ts" + ] + } + ], + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ] + }, + { + "id": 334, + "type": "timeseries", + "title": "Issues Triaged by Repo (Weekly)", + "description": "Weekly issues triaged (priority assigned), broken down by repository.", + "datasource": { + "type": "frser-sqlite-datasource", + "uid": "P2289B60D79A89B0C" + }, + "pluginVersion": "12.3.1", + "gridPos": { + "x": 12, + "y": 77, + "w": 12, + "h": 8 + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" }, - { - "matcher": { - "id": "byName", - "options": "value evals (External)" + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (First Response)" + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "value evals (Resolution Time)" + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "dark-green", - "mode": "fixed" - } - } - ] + "thresholdsStyle": { + "mode": "off" + } }, - { - "matcher": { - "id": "byName", - "options": "value .github" - }, - "properties": [ + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ { - "id": "color", - "value": { - "fixedColor": "#808080", - "mode": "fixed" - } + "color": "green", + "value": null } ] - }, + } + }, + "overrides": [ { "matcher": { "id": "byName", - "options": "value .github (Internal)" + "options": "sdk-python" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "#6C47FF", "mode": "fixed" } } @@ -13078,13 +10182,13 @@ { "matcher": { "id": "byName", - "options": "value .github (External)" + "options": "sdk-typescript" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "#2196F3", "mode": "fixed" } } @@ -13093,13 +10197,13 @@ { "matcher": { "id": "byName", - "options": "value .github (First Response)" + "options": "tools" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "#FF9800", "mode": "fixed" } } @@ -13108,13 +10212,13 @@ { "matcher": { "id": "byName", - "options": "value .github (Resolution Time)" + "options": "docs" }, "properties": [ { "id": "color", "value": { - "fixedColor": "#808080", + "fixedColor": "#4CAF50", "mode": "fixed" } } @@ -13123,13 +10227,13 @@ { "matcher": { "id": "byName", - "options": "value devtools" + "options": "evals" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "#E91E63", "mode": "fixed" } } @@ -13138,13 +10242,13 @@ { "matcher": { "id": "byName", - "options": "value devtools (Internal)" + "options": "samples" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "#00BCD4", "mode": "fixed" } } @@ -13153,13 +10257,13 @@ { "matcher": { "id": "byName", - "options": "value devtools (External)" + "options": "mcp-server" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "#9C27B0", "mode": "fixed" } } @@ -13168,13 +10272,13 @@ { "matcher": { "id": "byName", - "options": "value devtools (First Response)" + "options": "agent-builder" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "#FF5722", "mode": "fixed" } } @@ -13183,13 +10287,13 @@ { "matcher": { "id": "byName", - "options": "value devtools (Resolution Time)" + "options": "strandsagents.com" }, "properties": [ { "id": "color", "value": { - "fixedColor": "light-green", + "fixedColor": "#607D8B", "mode": "fixed" } } @@ -13197,13 +10301,6 @@ } ] }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 72 - }, - "id": 317, "options": { "legend": { "calcs": [], @@ -13217,9 +10314,9 @@ }, "targets": [ { - "queryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(issues_closed) as value\nFROM daily_metrics \nWHERE repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "queryText": "SELECT \n CAST(strftime('%s', date(pi.triaged_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n pi.repo as metric,\n COUNT(*) as value\nFROM project_items pi\nJOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\nWHERE pi.triaged_at IS NOT NULL AND pi.priority IS NOT NULL\n AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging')\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) <= $__to / 1000\nGROUP BY date(pi.triaged_at, 'weekday 0', '-6 days'), pi.repo\nORDER BY time ASC", "queryType": "table", - "rawQueryText": "SELECT \n CAST(strftime('%s', date(date, 'weekday 0', '-6 days')) as INTEGER) as time,\n repo as metric,\n SUM(issues_closed) as value\nFROM daily_metrics \nWHERE repo IN (${repo:singlequote}) \n AND CAST(strftime('%s', date) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', date) as INTEGER) <= $__to / 1000\nGROUP BY date(date, 'weekday 0', '-6 days'), repo\nORDER BY time ASC", + "rawQueryText": "SELECT \n CAST(strftime('%s', date(pi.triaged_at, 'weekday 0', '-6 days')) as INTEGER) as time,\n pi.repo as metric,\n COUNT(*) as value\nFROM project_items pi\nJOIN issues i ON pi.repo = i.repo AND pi.issue_number = i.number\nWHERE pi.triaged_at IS NOT NULL AND pi.priority IS NOT NULL\n AND i.repo IN (${repo:singlequote})\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) >= $__from / 1000\n AND CAST(strftime('%s', pi.triaged_at) as INTEGER) <= $__to / 1000\nGROUP BY date(pi.triaged_at, 'weekday 0', '-6 days'), pi.repo\nORDER BY time ASC", "refId": "A", "timeColumns": [ "time", @@ -13227,8 +10324,6 @@ ] } ], - "title": "Issues Closed by Repo (Weekly)", - "type": "timeseries", "transformations": [ { "id": "prepareTimeSeries", @@ -13289,4 +10384,4 @@ "title": "Overview", "uid": "adj9pgt", "version": 10 -} \ No newline at end of file +} diff --git a/community-dashboard/strands-metrics/src/client.rs b/community-dashboard/strands-metrics/src/client.rs index 96af1d9..7703718 100644 --- a/community-dashboard/strands-metrics/src/client.rs +++ b/community-dashboard/strands-metrics/src/client.rs @@ -7,6 +7,7 @@ use octocrab::{models, Octocrab, OctocrabBuilder}; use rusqlite::{params, Connection}; use serde::Deserialize; use serde_json::Value; +use std::collections::HashMap; use std::collections::HashSet; #[derive(Deserialize, Debug)] @@ -33,29 +34,101 @@ impl<'a> GitHubClient<'a> { pub async fn check_limits(&self) -> Result<()> { let rate = self.gh.ratelimit().get().await?; - let core = rate.resources.core; + // Check REST API rate limit + let core = rate.resources.core; if core.remaining < 50 { let reset = core.reset; let now = Utc::now().timestamp() as u64; let wait_secs = reset.saturating_sub(now) + 10; self.pb - .set_message(format!("Rate limit low. Sleeping {}s...", wait_secs)); + .set_message(format!("REST rate limit low. Sleeping {}s...", wait_secs)); tokio::time::sleep(tokio::time::Duration::from_secs(wait_secs)).await; } + + // Check GraphQL rate limit + if let Some(graphql) = rate.resources.graphql { + if graphql.remaining < 50 { + let reset = graphql.reset; + let now = Utc::now().timestamp() as u64; + let wait_secs = reset.saturating_sub(now) + 10; + self.pb + .set_message(format!("GraphQL rate limit low. Sleeping {}s...", wait_secs)); + tokio::time::sleep(tokio::time::Duration::from_secs(wait_secs)).await; + } + } + Ok(()) } + /// Execute a GraphQL query with retry + exponential backoff on errors. + async fn graphql_with_retry(&self, query: &str, max_retries: u32) -> Result { + let mut attempt = 0; + loop { + self.check_limits().await?; + let result: std::result::Result = self + .gh + .graphql(&serde_json::json!({ "query": query })) + .await; + + match result { + Ok(response) => { + // Check for rate limit errors in the GraphQL response + if let Some(errors) = response.get("errors") { + let err_str = errors.to_string(); + if (err_str.contains("rate limit") || err_str.contains("abuse")) + && attempt < max_retries + { + let wait = 2u64.pow(attempt) * 10; + self.pb.set_message(format!( + "GraphQL rate limited, retrying in {}s...", wait + )); + tokio::time::sleep(tokio::time::Duration::from_secs(wait)).await; + attempt += 1; + continue; + } + } + return Ok(response); + } + Err(e) => { + if attempt < max_retries { + let wait = 2u64.pow(attempt) * 5; + self.pb.set_message(format!( + "GraphQL error (attempt {}/{}), retrying in {}s: {}", + attempt + 1, max_retries, wait, e + )); + tokio::time::sleep(tokio::time::Duration::from_secs(wait)).await; + attempt += 1; + } else { + return Err(e.into()); + } + } + } + } + } + pub async fn sync_org(&mut self, org: &str) -> Result<()> { self.check_limits().await?; let repos = self.fetch_repos(org).await?; + let mut failures: Vec = Vec::new(); for repo in repos { self.pb.set_message(format!("Syncing {}", repo.name)); - self.sync_repo(org, &repo).await?; + if let Err(e) = self.sync_repo(org, &repo).await { + tracing::error!("Failed to sync {}: {}", repo.name, e); + self.pb.set_message(format!("WARN: {} sync failed, continuing...", repo.name)); + failures.push(repo.name.clone()); + } } // Sync GitHub Project V2 items (project #4 = Strands Agents board) - self.sync_project_items(org, 4).await?; + if let Err(e) = self.sync_project_items(org, 4).await { + tracing::error!("Failed to sync project items: {}", e); + failures.push("project_items".to_string()); + } + + if !failures.is_empty() { + tracing::warn!("Sync completed with failures: {:?}", failures); + } Ok(()) } @@ -725,10 +798,40 @@ impl<'a> GitHubClient<'a> { pub async fn sync_project_items(&self, org: &str, project_number: i32) -> Result<()> { self.pb.set_message(format!("Syncing project #{} items...", project_number)); - // Clear existing project items and re-sync fully each time. - // Project items don't have a reliable "updated since" filter via GraphQL. + // Snapshot existing priorities so we can detect NULL → non-NULL transitions + let mut old_priorities: HashMap> = HashMap::new(); + { + let mut stmt = self.db.prepare( + "SELECT node_id, priority FROM project_items" + )?; + let rows = stmt.query_map([], |row| { + Ok((row.get::<_, String>(0)?, row.get::<_, Option>(1)?)) + })?; + for row in rows { + let (nid, pri) = row?; + old_priorities.insert(nid, pri); + } + } + + // Snapshot existing triaged_at values to preserve them + let mut old_triaged: HashMap> = HashMap::new(); + { + let mut stmt = self.db.prepare( + "SELECT node_id, triaged_at FROM project_items" + )?; + let rows = stmt.query_map([], |row| { + Ok((row.get::<_, String>(0)?, row.get::<_, Option>(1)?)) + })?; + for row in rows { + let (nid, ta) = row?; + old_triaged.insert(nid, ta); + } + } + + // Clear and re-sync fully self.db.execute("DELETE FROM project_items", [])?; + let now = Utc::now().to_rfc3339(); let mut cursor: Option = None; let mut total = 0u64; @@ -777,8 +880,7 @@ impl<'a> GitHubClient<'a> { ); let response: Value = self - .gh - .graphql(&serde_json::json!({ "query": query })) + .graphql_with_retry(&query, 3) .await?; // Check for GraphQL errors @@ -842,10 +944,26 @@ impl<'a> GitHubClient<'a> { let priority = node.pointer("/priority/name").and_then(|v| v.as_str()); let status = node.pointer("/status/name").and_then(|v| v.as_str()); + // Determine triaged_at: + // 1. If we already had a triaged_at, preserve it + // 2. If priority was NULL before and is now non-NULL, set triaged_at = now + // 3. Otherwise leave NULL + let triaged_at = if let Some(existing) = old_triaged.get(node_id).and_then(|t| t.as_deref()) { + Some(existing.to_string()) + } else if priority.is_some() { + let was_null = old_priorities + .get(node_id) + .map(|p| p.is_none()) + .unwrap_or(true); // new item with priority = treat as newly triaged + if was_null { Some(now.clone()) } else { None } + } else { + None + }; + self.db.execute( - "INSERT OR REPLACE INTO project_items (node_id, repo, issue_number, priority, status, updated_at) - VALUES (?1, ?2, ?3, ?4, ?5, ?6)", - params![node_id, repo, issue_number, priority, status, updated_at], + "INSERT OR REPLACE INTO project_items (node_id, repo, issue_number, priority, status, updated_at, triaged_at) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", + params![node_id, repo, issue_number, priority, status, updated_at, triaged_at], )?; total += 1; } @@ -871,6 +989,157 @@ impl<'a> GitHubClient<'a> { Ok(()) } + /// Backfill triaged_at timestamps by checking issue timeline events. + /// For each project item that has a priority but no triaged_at, fetches the + /// issue timeline to find when the priority field was first set. + pub async fn backfill_triage_timestamps(&self, org: &str) -> Result<()> { + // Find items that have priority set but no triaged_at + let items: Vec<(String, String, i64)> = { + let mut stmt = self.db.prepare( + "SELECT node_id, repo, issue_number FROM project_items + WHERE priority IS NOT NULL AND triaged_at IS NULL" + )?; + let result = stmt.query_map([], |row| { + Ok(( + row.get::<_, String>(0)?, + row.get::<_, String>(1)?, + row.get::<_, i64>(2)?, + )) + })? + .collect::, _>>()?; + result + }; + + let total = items.len(); + self.pb.set_message(format!("Backfilling triage timestamps for {} items...", total)); + + for (i, (node_id, repo, issue_number)) in items.iter().enumerate() { + if i % 10 == 0 { + self.pb.set_message(format!( + "Backfilling triage timestamps... {}/{}", i, total + )); + } + + self.check_limits().await?; + + // Fetch issue timeline events looking for project field changes + let triaged_at = self + .find_triage_timestamp(org, repo, *issue_number as u64) + .await?; + + if let Some(ts) = triaged_at { + self.db.execute( + "UPDATE project_items SET triaged_at = ?1 WHERE node_id = ?2", + params![ts, node_id], + )?; + } else { + // Fallback: use the issue's created_at as a rough approximation + // (better than nothing for historical data) + let created_at: Option = self.db.query_row( + "SELECT created_at FROM issues WHERE repo = ?1 AND number = ?2", + params![repo, issue_number], + |row| row.get(0), + ).ok(); + if let Some(ca) = created_at { + self.db.execute( + "UPDATE project_items SET triaged_at = ?1 WHERE node_id = ?2", + params![ca, node_id], + )?; + } + } + } + + self.pb.set_message(format!("Backfilled triage timestamps for {} items", total)); + Ok(()) + } + + /// Look through issue timeline events to find when the issue was triaged. + /// Checks for: 1) priority field change, 2) added to project (as proxy for triage). + async fn find_triage_timestamp( + &self, + org: &str, + repo: &str, + issue_number: u64, + ) -> Result> { + let mut page = 1u32; + let mut added_to_project_at: Option = None; + + loop { + self.check_limits().await?; + + let route = format!( + "/repos/{}/{}/issues/{}/timeline", + org, repo, issue_number + ); + + let result: Result, _> = self + .gh + .get( + &route, + Some(&serde_json::json!({ + "per_page": 100, + "page": page + })), + ) + .await; + + let events = match result { + Ok(e) => e, + Err(e) => { + if Self::is_missing_resource(&e) { + return Ok(None); + } + tracing::warn!( + "Error fetching timeline for {}/{}#{}: {}", + org, repo, issue_number, e + ); + return Ok(None); + } + }; + + if events.is_empty() { + break; + } + + for event in &events { + let event_type = event.get("event").and_then(|v| v.as_str()).unwrap_or(""); + + // Best signal: explicit priority field change + if event_type == "project_v2_item_field_value_changed" { + let field_name = event + .pointer("/project_v2_item_field_value_change/field_name") + .and_then(|v| v.as_str()) + .unwrap_or(""); + + if field_name == "Priority" { + let created_at = event + .get("created_at") + .and_then(|v| v.as_str()) + .unwrap_or(""); + if !created_at.is_empty() { + return Ok(Some(created_at.to_string())); + } + } + } + + // Fallback signal: when the issue was added to the project board + if event_type == "added_to_project_v2" && added_to_project_at.is_none() { + if let Some(ts) = event.get("created_at").and_then(|v| v.as_str()) { + added_to_project_at = Some(ts.to_string()); + } + } + } + + if events.len() < 100 { + break; + } + page += 1; + } + + // Return added_to_project timestamp as proxy for triage time + Ok(added_to_project_at) + } + fn is_missing_resource(err: &octocrab::Error) -> bool { match err { octocrab::Error::GitHub { source, .. } => { diff --git a/community-dashboard/strands-metrics/src/db.rs b/community-dashboard/strands-metrics/src/db.rs index b9e7320..f9eb0fe 100644 --- a/community-dashboard/strands-metrics/src/db.rs +++ b/community-dashboard/strands-metrics/src/db.rs @@ -131,7 +131,8 @@ pub fn init_db>(path: P) -> Result { issue_number INTEGER NOT NULL, priority TEXT, status TEXT, - updated_at TEXT NOT NULL + updated_at TEXT NOT NULL, + triaged_at TEXT )", [], )?; @@ -201,6 +202,7 @@ pub fn init_db>(path: P) -> Result { // ── Migrations for existing databases ────────────────────────────── let _ = conn.execute("ALTER TABLE daily_metrics ADD COLUMN weekly_community_contributors INTEGER DEFAULT 0", []); let _ = conn.execute("ALTER TABLE daily_metrics ADD COLUMN cumulative_community_contributors INTEGER DEFAULT 0", []); + let _ = conn.execute("ALTER TABLE project_items ADD COLUMN triaged_at TEXT", []); Ok(conn) } diff --git a/community-dashboard/strands-metrics/src/main.rs b/community-dashboard/strands-metrics/src/main.rs index 36b4d1e..98f1c6c 100644 --- a/community-dashboard/strands-metrics/src/main.rs +++ b/community-dashboard/strands-metrics/src/main.rs @@ -66,6 +66,8 @@ enum Commands { #[clap(long, default_value = "../packages.yaml")] config_path: PathBuf, }, + /// Backfill triaged_at timestamps from issue timeline events. + BackfillTriage, } /// Create a spinner progress bar with consistent styling @@ -236,6 +238,18 @@ async fn main() -> Result<()> { println!("\nBackfill complete!"); } + Commands::BackfillTriage => { + let gh_token = std::env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN must be set"); + let octocrab = OctocrabBuilder::new().personal_token(gh_token).build()?; + + let m = Arc::new(MultiProgress::new()); + let pb = create_spinner(&m, "Backfilling triage timestamps..."); + + let client = GitHubClient::new(octocrab, &mut conn, pb.clone()); + client.backfill_triage_timestamps(ORG).await?; + + pb.finish_with_message("Triage backfill complete."); + } } Ok(()) From 1ab1830833ce3fc86f53556eb3db44f5cc15509c Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Fri, 27 Feb 2026 12:07:07 -0500 Subject: [PATCH 17/22] feat: add triage & responsiveness dashboard sections, fix layout - Add Triage section with stat panels, bargauges, velocity, per-repo breakdowns - Add Responsiveness section with awaiting response/review panels - Fix Volume row position (y=49, after Adoption) - Order Priority Issues by severity (Sev2 > On-Call > High) - Add backfill-triage to entrypoint recompute flow - Add RECOMPUTE_METRICS env var to CDK (temporary) --- community-dashboard/cdk/lib/community-dashboard-stack.ts | 3 +++ community-dashboard/docker/entrypoint.sh | 3 +++ .../provisioning/dashboards/general/health.json | 6 +++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/community-dashboard/cdk/lib/community-dashboard-stack.ts b/community-dashboard/cdk/lib/community-dashboard-stack.ts index 0eb673c..5deabcf 100644 --- a/community-dashboard/cdk/lib/community-dashboard-stack.ts +++ b/community-dashboard/cdk/lib/community-dashboard-stack.ts @@ -112,6 +112,9 @@ export class CommunityDashboardStack extends cdk.Stack { logRetention: logs.RetentionDays.TWO_WEEKS, }), portMappings: [{ containerPort: 3000 }], + environment: { + RECOMPUTE_METRICS: "true", + }, secrets: { GITHUB_TOKEN: ecs.Secret.fromSecretsManager(githubSecret), }, diff --git a/community-dashboard/docker/entrypoint.sh b/community-dashboard/docker/entrypoint.sh index 318021b..a054d00 100644 --- a/community-dashboard/docker/entrypoint.sh +++ b/community-dashboard/docker/entrypoint.sh @@ -57,6 +57,9 @@ if [ "${RECOMPUTE_METRICS:-false}" = "true" ]; then echo "[entrypoint] Running sync + full recompute now..." strands-metrics --db-path "$DB_PATH" sync || \ echo "[entrypoint] WARNING: Recompute sync failed (will retry on next cron run)." + echo "[entrypoint] Running triage timestamp backfill..." + strands-metrics --db-path "$DB_PATH" backfill-triage || \ + echo "[entrypoint] WARNING: Triage backfill failed (can be run manually later)." fi fi diff --git a/community-dashboard/provisioning/dashboards/general/health.json b/community-dashboard/provisioning/dashboards/general/health.json index d5f13fd..7c4578c 100644 --- a/community-dashboard/provisioning/dashboards/general/health.json +++ b/community-dashboard/provisioning/dashboards/general/health.json @@ -537,7 +537,7 @@ "h": 1, "w": 24, "x": 0, - "y": 27 + "y": 49 }, "id": 100, "panels": [], @@ -934,9 +934,9 @@ "pluginVersion": "12.3.1", "targets": [ { - "queryText": "SELECT i.repo || ' (' || pi.priority || ')' as metric, COUNT(*) as count FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority IN ('Sev2', 'On-Call', 'High') AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') GROUP BY i.repo, pi.priority ORDER BY count DESC", + "queryText": "SELECT i.repo || ' (' || pi.priority || ')' as metric, COUNT(*) as count FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority IN ('Sev2', 'On-Call', 'High') AND i.repo IN ('agent-builder','agent-sop','docs','evals','mcp-server','private-docs-staging','private-sdk-python-staging','private-sdk-typescript-staging','private-tools-staging','samples','sdk-python','sdk-typescript','strands-action','strandsagents.com','tools','.github','private-samples-staging','private-strands-action-staging') GROUP BY i.repo, pi.priority ORDER BY CASE pi.priority WHEN 'Sev2' THEN 1 WHEN 'On-Call' THEN 2 WHEN 'High' THEN 3 ELSE 4 END, count DESC", "queryType": "table", - "rawQueryText": "SELECT i.repo || ' (' || pi.priority || ')' as metric, COUNT(*) as count FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority IN ('Sev2', 'On-Call', 'High') AND i.repo IN (${repo:singlequote}) GROUP BY i.repo, pi.priority ORDER BY count DESC", + "rawQueryText": "SELECT i.repo || ' (' || pi.priority || ')' as metric, COUNT(*) as count FROM issues i JOIN project_items pi ON i.repo = pi.repo AND i.number = pi.issue_number WHERE i.state = 'open' AND pi.priority IN ('Sev2', 'On-Call', 'High') AND i.repo IN (${repo:singlequote}) GROUP BY i.repo, pi.priority ORDER BY CASE pi.priority WHEN 'Sev2' THEN 1 WHEN 'On-Call' THEN 2 WHEN 'High' THEN 3 ELSE 4 END, count DESC", "refId": "A", "timeColumns": [ "time", From eb3c14d00af32b418fb66ecdfd8bb7640f9d93f8 Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Fri, 27 Feb 2026 12:10:47 -0500 Subject: [PATCH 18/22] docs: add backfill-triage command and triage features to README/AGENTS --- community-dashboard/AGENTS.md | 8 ++++++-- community-dashboard/README.md | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/community-dashboard/AGENTS.md b/community-dashboard/AGENTS.md index 8814205..bf96286 100644 --- a/community-dashboard/AGENTS.md +++ b/community-dashboard/AGENTS.md @@ -51,6 +51,9 @@ cargo run --release -- sync-downloads # Backfill historical downloads (PyPI ~180d, npm ~365d) cargo run --release -- backfill-downloads +# Backfill triage timestamps from GitHub timeline API +GITHUB_TOKEN=ghp_xxx cargo run --release -- backfill-triage + # Load goal thresholds / team members cargo run --release -- load-goals cargo run --release -- load-team @@ -137,7 +140,7 @@ npx tsc --noEmit | Module | Responsibility | |---|---| | `main.rs` | CLI entry point (clap), dispatches subcommands | -| `client.rs` | GitHub API client via octocrab | +| `client.rs` | GitHub API client via octocrab, GraphQL with retry/backoff | | `db.rs` | SQLite schema init and migrations | | `downloads.rs` | PyPI / npm download stat fetching | | `goals.rs` | Goal thresholds and team member management | @@ -172,7 +175,8 @@ runs daily at 06:00 UTC as a de-facto integration test: 5. `cargo run --release -- load-team` 6. Commits updated `metrics.db` back to the repo. -Required secret: `METRICS_PAT` (GitHub PAT with org read access). +Required secret: `METRICS_PAT` (GitHub PAT with org read access +and `read:project` scope for project items sync). ## Security & Compliance diff --git a/community-dashboard/README.md b/community-dashboard/README.md index 8afba8d..94a8cd4 100644 --- a/community-dashboard/README.md +++ b/community-dashboard/README.md @@ -123,6 +123,9 @@ cargo run --release -- load-team # Backfill historical downloads (PyPI: ~180 days, npm: ~365 days) cargo run --release -- backfill-downloads +# Backfill triage timestamps from GitHub timeline API (one-time) +GITHUB_TOKEN=ghp_xxx cargo run --release -- backfill-triage + # Run arbitrary SQL queries cargo run --release -- query "SELECT repo, SUM(prs_merged) FROM daily_metrics GROUP BY repo" ``` @@ -139,6 +142,7 @@ cargo run --release -- query "SELECT repo, SUM(prs_merged) FROM daily_metrics GR | `load-team [path]` | Load team members from YAML or `--members alice,bob` (default: `../team.yaml`) | | `sync-downloads` | Sync recent package downloads from PyPI and npm (default: 30 days) | | `backfill-downloads` | Backfill historical download data (PyPI: ~180 days, npm: ~365 days) | +| `backfill-triage` | Backfill `triaged_at` timestamps from GitHub timeline API (one-time) | ### Global flags @@ -151,7 +155,7 @@ cargo run --release -- query "SELECT repo, SUM(prs_merged) FROM daily_metrics GR ### General - **Executive Summary** -- High-level org overview: total stars, open PRs/issues, stale PR count, contributor trends -- **Health** -- Org health metrics with goal lines: merge time, cycle time, CI failure rate, community PR %, contributor retention, response times +- **Health** -- Org health metrics with goal lines: merge time, cycle time, CI failure rate, community PR %, contributor retention, response times, triage velocity, and responsiveness tracking ### SDKs @@ -255,7 +259,7 @@ The included workflow (`.github/workflows/community-dashboard.yaml`) runs daily 4. Loads goals and team configuration 5. Commits the updated `metrics.db` back to the repository -Required secret: `METRICS_PAT` -- a GitHub PAT with read access to the `strands-agents` org. +Required secret: `METRICS_PAT` -- a GitHub PAT with read access to the `strands-agents` org and `read:project` scope for project items sync. ## Data Flow From ffed5d8e0679b515799224509bc1fd34ca51056d Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Mon, 2 Mar 2026 10:46:53 -0500 Subject: [PATCH 19/22] feat: TTY-aware logging for container environments - Add atty dependency for TTY detection - Use hidden progress bars + tracing::info in non-TTY (container/CI) - Add log_progress helper to dual-write spinner + tracing - Fix triage timestamp logic for new project items --- .../strands-metrics/Cargo.lock | 43 +++++++++++++++++ .../strands-metrics/Cargo.toml | 1 + .../strands-metrics/src/client.rs | 46 ++++++++++--------- .../strands-metrics/src/main.rs | 36 +++++++++++---- 4 files changed, 94 insertions(+), 32 deletions(-) diff --git a/community-dashboard/strands-metrics/Cargo.lock b/community-dashboard/strands-metrics/Cargo.lock index c0d1f33..d0a2457 100644 --- a/community-dashboard/strands-metrics/Cargo.lock +++ b/community-dashboard/strands-metrics/Cargo.lock @@ -93,6 +93,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -766,6 +777,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -2132,6 +2152,7 @@ name = "strands-metrics" version = "0.1.0" dependencies = [ "anyhow", + "atty", "chrono", "clap", "http", @@ -2699,6 +2720,28 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.62.2" diff --git a/community-dashboard/strands-metrics/Cargo.toml b/community-dashboard/strands-metrics/Cargo.toml index 1e4f51b..010f3ce 100644 --- a/community-dashboard/strands-metrics/Cargo.toml +++ b/community-dashboard/strands-metrics/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] anyhow = "1.0" +atty = "0.2" chrono = { version = "0.4", features = ["serde"] } clap = { version = "4.5", features = ["derive"] } http = "1.4.0" diff --git a/community-dashboard/strands-metrics/src/client.rs b/community-dashboard/strands-metrics/src/client.rs index 7703718..a86b89f 100644 --- a/community-dashboard/strands-metrics/src/client.rs +++ b/community-dashboard/strands-metrics/src/client.rs @@ -32,6 +32,12 @@ impl<'a> GitHubClient<'a> { Self { gh, db, pb } } + /// Update spinner message and also log to tracing (visible in non-TTY/container mode). + fn log_progress(&self, msg: &str) { + self.pb.set_message(msg.to_string()); + tracing::info!("{}", msg); + } + pub async fn check_limits(&self) -> Result<()> { let rate = self.gh.ratelimit().get().await?; @@ -41,8 +47,7 @@ impl<'a> GitHubClient<'a> { let reset = core.reset; let now = Utc::now().timestamp() as u64; let wait_secs = reset.saturating_sub(now) + 10; - self.pb - .set_message(format!("REST rate limit low. Sleeping {}s...", wait_secs)); + self.log_progress(&format!("REST rate limit low. Sleeping {}s...", wait_secs)); tokio::time::sleep(tokio::time::Duration::from_secs(wait_secs)).await; } @@ -52,8 +57,7 @@ impl<'a> GitHubClient<'a> { let reset = graphql.reset; let now = Utc::now().timestamp() as u64; let wait_secs = reset.saturating_sub(now) + 10; - self.pb - .set_message(format!("GraphQL rate limit low. Sleeping {}s...", wait_secs)); + self.log_progress(&format!("GraphQL rate limit low. Sleeping {}s...", wait_secs)); tokio::time::sleep(tokio::time::Duration::from_secs(wait_secs)).await; } } @@ -80,7 +84,7 @@ impl<'a> GitHubClient<'a> { && attempt < max_retries { let wait = 2u64.pow(attempt) * 10; - self.pb.set_message(format!( + self.log_progress(&format!( "GraphQL rate limited, retrying in {}s...", wait )); tokio::time::sleep(tokio::time::Duration::from_secs(wait)).await; @@ -93,7 +97,7 @@ impl<'a> GitHubClient<'a> { Err(e) => { if attempt < max_retries { let wait = 2u64.pow(attempt) * 5; - self.pb.set_message(format!( + self.log_progress(&format!( "GraphQL error (attempt {}/{}), retrying in {}s: {}", attempt + 1, max_retries, wait, e )); @@ -112,10 +116,10 @@ impl<'a> GitHubClient<'a> { let repos = self.fetch_repos(org).await?; let mut failures: Vec = Vec::new(); for repo in repos { - self.pb.set_message(format!("Syncing {}", repo.name)); + self.log_progress(&format!("Syncing {}", repo.name)); if let Err(e) = self.sync_repo(org, &repo).await { tracing::error!("Failed to sync {}: {}", repo.name, e); - self.pb.set_message(format!("WARN: {} sync failed, continuing...", repo.name)); + self.log_progress(&format!("WARN: {} sync failed, continuing...", repo.name)); failures.push(repo.name.clone()); } } @@ -137,7 +141,7 @@ impl<'a> GitHubClient<'a> { self.check_limits().await?; let repos = self.fetch_repos(org).await?; for repo in repos { - self.pb.set_message(format!("Sweeping {}", repo.name)); + self.log_progress(&format!("Sweeping {}", repo.name)); self.sweep_repo(org, &repo).await?; } Ok(()) @@ -796,7 +800,7 @@ impl<'a> GitHubClient<'a> { /// Sync GitHub Project V2 items (org-level, not per-repo). /// Fetches priority and status fields from the specified project number. pub async fn sync_project_items(&self, org: &str, project_number: i32) -> Result<()> { - self.pb.set_message(format!("Syncing project #{} items...", project_number)); + self.log_progress(&format!("Syncing project #{} items...", project_number)); // Snapshot existing priorities so we can detect NULL → non-NULL transitions let mut old_priorities: HashMap> = HashMap::new(); @@ -946,15 +950,14 @@ impl<'a> GitHubClient<'a> { // Determine triaged_at: // 1. If we already had a triaged_at, preserve it - // 2. If priority was NULL before and is now non-NULL, set triaged_at = now - // 3. Otherwise leave NULL + // 2. If item existed before with NULL priority and now has priority, set triaged_at = now + // 3. Brand new items (not in old_priorities) → leave NULL for backfill to handle + // 4. Otherwise leave NULL let triaged_at = if let Some(existing) = old_triaged.get(node_id).and_then(|t| t.as_deref()) { Some(existing.to_string()) - } else if priority.is_some() { - let was_null = old_priorities - .get(node_id) - .map(|p| p.is_none()) - .unwrap_or(true); // new item with priority = treat as newly triaged + } else if priority.is_some() && old_priorities.contains_key(node_id) { + // Item existed before — check if priority transitioned from NULL + let was_null = old_priorities.get(node_id).map(|p| p.is_none()).unwrap_or(false); if was_null { Some(now.clone()) } else { None } } else { None @@ -984,8 +987,7 @@ impl<'a> GitHubClient<'a> { } } - self.pb - .set_message(format!("Synced {} project items", total)); + self.log_progress(&format!("Synced {} project items", total)); Ok(()) } @@ -1011,11 +1013,11 @@ impl<'a> GitHubClient<'a> { }; let total = items.len(); - self.pb.set_message(format!("Backfilling triage timestamps for {} items...", total)); + self.log_progress(&format!("Backfilling triage timestamps for {} items...", total)); for (i, (node_id, repo, issue_number)) in items.iter().enumerate() { if i % 10 == 0 { - self.pb.set_message(format!( + self.log_progress(&format!( "Backfilling triage timestamps... {}/{}", i, total )); } @@ -1049,7 +1051,7 @@ impl<'a> GitHubClient<'a> { } } - self.pb.set_message(format!("Backfilled triage timestamps for {} items", total)); + self.log_progress(&format!("Backfilled triage timestamps for {} items", total)); Ok(()) } diff --git a/community-dashboard/strands-metrics/src/main.rs b/community-dashboard/strands-metrics/src/main.rs index 98f1c6c..5efef8e 100644 --- a/community-dashboard/strands-metrics/src/main.rs +++ b/community-dashboard/strands-metrics/src/main.rs @@ -5,6 +5,7 @@ mod downloads; mod goals; use anyhow::Result; +use atty::Stream; use clap::{Parser, Subcommand}; use client::GitHubClient; use db::init_db; @@ -70,23 +71,34 @@ enum Commands { BackfillTriage, } -/// Create a spinner progress bar with consistent styling +/// Create a spinner progress bar with consistent styling. +/// In non-TTY environments (containers, CI), uses a hidden progress bar +/// and logs messages to stderr instead. fn create_spinner(m: &Arc, message: &str) -> ProgressBar { - let sty = ProgressStyle::with_template("{spinner:.green} {msg}") - .unwrap() - .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ "); - let pb = m.add(ProgressBar::new_spinner()); - pb.set_style(sty); - pb.enable_steady_tick(std::time::Duration::from_millis(120)); - pb.set_message(message.to_string()); - pb + if atty::is(Stream::Stderr) { + let sty = ProgressStyle::with_template("{spinner:.green} {msg}") + .unwrap() + .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ "); + let pb = m.add(ProgressBar::new_spinner()); + pb.set_style(sty); + pb.enable_steady_tick(std::time::Duration::from_millis(120)); + pb.set_message(message.to_string()); + pb + } else { + eprintln!("[metrics] {}", message); + let pb = m.add(ProgressBar::hidden()); + pb + } } #[tokio::main] async fn main() -> Result<()> { + let is_tty = atty::is(Stream::Stderr); + tracing_subscriber::fmt() .with_writer(std::io::stderr) - .with_max_level(LevelFilter::WARN) + .with_max_level(if is_tty { LevelFilter::WARN } else { LevelFilter::INFO }) + .with_ansi(is_tty) .init(); let args = Cli::parse(); @@ -106,9 +118,11 @@ async fn main() -> Result<()> { client.sync_org(ORG).await?; pb.set_message("Calculating metrics..."); + tracing::info!("Calculating metrics..."); aggregates::compute_metrics(&conn)?; pb.finish_with_message("Done!"); + tracing::info!("Sync complete."); } Commands::Sweep => { let gh_token = std::env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN must be set"); @@ -121,6 +135,7 @@ async fn main() -> Result<()> { client.sweep_org(ORG).await?; pb.finish_with_message("Sweep complete."); + tracing::info!("Sweep complete."); } Commands::Query { sql } => { let mut stmt = conn.prepare(&sql)?; @@ -249,6 +264,7 @@ async fn main() -> Result<()> { client.backfill_triage_timestamps(ORG).await?; pb.finish_with_message("Triage backfill complete."); + tracing::info!("Triage backfill complete."); } } From 48c2c3eb6697d7e0e1e4b8157a82690acfde2154 Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Mon, 2 Mar 2026 10:47:06 -0500 Subject: [PATCH 20/22] feat: split Docker images into Grafana and metrics - Dockerfile.grafana: lightweight Grafana-only image for serving - Dockerfile.metrics: multi-stage Rust build for sync tasks - Add backfill-triage step to sync-all.sh --- community-dashboard/docker/Dockerfile.grafana | 25 ++++++++++++++ community-dashboard/docker/Dockerfile.metrics | 33 +++++++++++++++++++ community-dashboard/docker/sync-all.sh | 3 ++ 3 files changed, 61 insertions(+) create mode 100644 community-dashboard/docker/Dockerfile.grafana create mode 100644 community-dashboard/docker/Dockerfile.metrics diff --git a/community-dashboard/docker/Dockerfile.grafana b/community-dashboard/docker/Dockerfile.grafana new file mode 100644 index 0000000..b545e5f --- /dev/null +++ b/community-dashboard/docker/Dockerfile.grafana @@ -0,0 +1,25 @@ +# ============================================================================= +# Grafana-only image — no Rust build, no sync logic +# ============================================================================= +FROM grafana/grafana:latest + +USER root + +# Copy Grafana provisioning configs +COPY provisioning/datasources/ /etc/grafana/provisioning/datasources/ +COPY provisioning/dashboards/ /etc/grafana/provisioning/dashboards/ + +# Create the data directory for EFS / local mount +RUN mkdir -p /var/lib/grafana/data + +# Grafana configuration via environment variables +ENV GF_INSTALL_PLUGINS=frser-sqlite-datasource +ENV GF_PLUGIN_FRSER_SQLITE_DATASOURCE_ALLOW_LOCAL_MODE=true +ENV GF_AUTH_ANONYMOUS_ENABLED=true +ENV GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer +ENV GF_AUTH_BASIC_ENABLED=false +ENV GF_AUTH_DISABLE_LOGIN_FORM=true +ENV GF_USERS_ALLOW_SIGN_UP=false +ENV GF_SECURITY_ALLOW_EMBEDDING=true + +EXPOSE 3000 diff --git a/community-dashboard/docker/Dockerfile.metrics b/community-dashboard/docker/Dockerfile.metrics new file mode 100644 index 0000000..a5d4419 --- /dev/null +++ b/community-dashboard/docker/Dockerfile.metrics @@ -0,0 +1,33 @@ +# ============================================================================= +# Stage 1: Build the strands-metrics Rust binary +# ============================================================================= +FROM rust:1.88-alpine AS builder + +RUN apk add --no-cache musl-dev pkgconfig openssl-dev openssl-libs-static + +WORKDIR /build + +COPY strands-metrics/Cargo.toml strands-metrics/Cargo.lock* ./ +COPY strands-metrics/src/ ./src/ + +RUN cargo build --release + +# ============================================================================= +# Stage 2: Minimal metrics runner +# ============================================================================= +FROM alpine:3.21 + +RUN apk add --no-cache ca-certificates sqlite + +COPY --from=builder /build/target/release/strands-metrics /usr/local/bin/strands-metrics + +# Copy configuration files +COPY goals.yaml /etc/strands/goals.yaml +COPY team.yaml /etc/strands/team.yaml +COPY packages.yaml /etc/strands/packages.yaml + +# Copy the sync script +COPY docker/sync-all.sh /usr/local/bin/sync-all.sh +RUN chmod +x /usr/local/bin/sync-all.sh + +ENTRYPOINT ["sync-all.sh"] diff --git a/community-dashboard/docker/sync-all.sh b/community-dashboard/docker/sync-all.sh index a000e26..10b462c 100644 --- a/community-dashboard/docker/sync-all.sh +++ b/community-dashboard/docker/sync-all.sh @@ -9,6 +9,9 @@ CONFIG_DIR="/etc/strands" echo "[sync-all] Starting GitHub data sync..." strands-metrics --db-path "$DB_PATH" sync +echo "[sync-all] Backfilling triage timestamps..." +strands-metrics --db-path "$DB_PATH" backfill-triage + echo "[sync-all] Running garbage collection..." strands-metrics --db-path "$DB_PATH" sweep From 51dbeafa7c354ddaca88504a41f04e499a127d3d Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Mon, 2 Mar 2026 10:47:21 -0500 Subject: [PATCH 21/22] feat: split CDK into Grafana service + scheduled metrics task, add WAF rate-limit - Grafana runs as always-on Fargate service (no secrets needed) - Metrics sync runs as on-demand Fargate task via EventBridge (daily 06:00 UTC) - Add WAF WebACL with rate-limit rule (300 req/5min per IP) on CloudFront - Add manual run-task command output for ad-hoc syncs --- community-dashboard/cdk/cdk.context.json | 8 + .../cdk/lib/community-dashboard-stack.ts | 188 +++++++++++++----- 2 files changed, 144 insertions(+), 52 deletions(-) diff --git a/community-dashboard/cdk/cdk.context.json b/community-dashboard/cdk/cdk.context.json index f4ec970..33b7ca1 100644 --- a/community-dashboard/cdk/cdk.context.json +++ b/community-dashboard/cdk/cdk.context.json @@ -12,5 +12,13 @@ "us-east-1d", "us-east-1e", "us-east-1f" + ], + "availability-zones:account=418272784382:region=us-east-1": [ + "us-east-1a", + "us-east-1b", + "us-east-1c", + "us-east-1d", + "us-east-1e", + "us-east-1f" ] } diff --git a/community-dashboard/cdk/lib/community-dashboard-stack.ts b/community-dashboard/cdk/lib/community-dashboard-stack.ts index 5deabcf..8b30083 100644 --- a/community-dashboard/cdk/lib/community-dashboard-stack.ts +++ b/community-dashboard/cdk/lib/community-dashboard-stack.ts @@ -2,12 +2,15 @@ import * as cdk from "aws-cdk-lib"; import * as ec2 from "aws-cdk-lib/aws-ec2"; import * as ecs from "aws-cdk-lib/aws-ecs"; import * as efs from "aws-cdk-lib/aws-efs"; +import * as events from "aws-cdk-lib/aws-events"; +import * as targets from "aws-cdk-lib/aws-events-targets"; import * as apigwv2 from "aws-cdk-lib/aws-apigatewayv2"; import * as cloudfront from "aws-cdk-lib/aws-cloudfront"; import * as origins from "aws-cdk-lib/aws-cloudfront-origins"; import * as logs from "aws-cdk-lib/aws-logs"; import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"; import * as servicediscovery from "aws-cdk-lib/aws-servicediscovery"; +import * as wafv2 from "aws-cdk-lib/aws-wafv2"; import { Construct } from "constructs"; import * as path from "path"; @@ -24,7 +27,7 @@ export class CommunityDashboardStack extends cdk.Stack { throw new Error( "GITHUB_SECRET_ARN environment variable or 'githubSecretArn' CDK context must be set.\n" + "Create the secret first:\n" + - ' aws secretsmanager create-secret --name strands-grafana/github-token --secret-string "ghp_xxx" --region us-east-1' + ' aws secretsmanager create-secret --name strands-grafana/github-token --secret-string "ghp_xxx" --region us-west-2' ); } @@ -77,47 +80,46 @@ export class CommunityDashboardStack extends cdk.Stack { containerInsights: true, }); - // ── Task Definition ───────────────────────────────────────────────── - const taskDef = new ecs.FargateTaskDefinition(this, "TaskDef", { + // Helper: add EFS volume + mount to a task definition + const addEfsVolume = (taskDef: ecs.FargateTaskDefinition) => { + taskDef.addVolume({ + name: "metrics-data", + efsVolumeConfiguration: { + fileSystemId: fileSystem.fileSystemId, + transitEncryption: "ENABLED", + authorizationConfig: { + accessPointId: accessPoint.accessPointId, + iam: "ENABLED", + }, + }, + }); + fileSystem.grant( + taskDef.taskRole, + "elasticfilesystem:ClientMount", + "elasticfilesystem:ClientWrite", + "elasticfilesystem:ClientRootAccess" + ); + }; + + // ═════════════════════════════════════════════════════════════════════ + // 1. Grafana Service (always-on) — just serves dashboards + // ═════════════════════════════════════════════════════════════════════ + const grafanaTaskDef = new ecs.FargateTaskDefinition(this, "GrafanaTaskDef", { cpu: 512, memoryLimitMiB: 1024, }); + addEfsVolume(grafanaTaskDef); - taskDef.addVolume({ - name: "metrics-data", - efsVolumeConfiguration: { - fileSystemId: fileSystem.fileSystemId, - transitEncryption: "ENABLED", - authorizationConfig: { - accessPointId: accessPoint.accessPointId, - iam: "ENABLED", - }, - }, - }); - - fileSystem.grant( - taskDef.taskRole, - "elasticfilesystem:ClientMount", - "elasticfilesystem:ClientWrite", - "elasticfilesystem:ClientRootAccess" - ); - - const container = taskDef.addContainer("grafana", { + const grafanaContainer = grafanaTaskDef.addContainer("grafana", { image: ecs.ContainerImage.fromAsset(path.join(__dirname, "../../"), { - file: "docker/Dockerfile", + file: "docker/Dockerfile.grafana", platform: cdk.aws_ecr_assets.Platform.LINUX_AMD64, }), logging: ecs.LogDrivers.awsLogs({ - streamPrefix: "community-dashboard", + streamPrefix: "grafana", logRetention: logs.RetentionDays.TWO_WEEKS, }), portMappings: [{ containerPort: 3000 }], - environment: { - RECOMPUTE_METRICS: "true", - }, - secrets: { - GITHUB_TOKEN: ecs.Secret.fromSecretsManager(githubSecret), - }, healthCheck: { command: [ "CMD-SHELL", @@ -126,20 +128,19 @@ export class CommunityDashboardStack extends cdk.Stack { interval: cdk.Duration.seconds(30), timeout: cdk.Duration.seconds(5), retries: 3, - startPeriod: cdk.Duration.seconds(120), + startPeriod: cdk.Duration.seconds(60), }, }); - container.addMountPoints({ + grafanaContainer.addMountPoints({ sourceVolume: "metrics-data", containerPath: "/var/lib/grafana/data", readOnly: false, }); - // ── Fargate Service with Cloud Map service discovery ──────────────── - const service = new ecs.FargateService(this, "Service", { + const grafanaService = new ecs.FargateService(this, "GrafanaService", { cluster, - taskDefinition: taskDef, + taskDefinition: grafanaTaskDef, desiredCount: 1, assignPublicIp: false, platformVersion: ecs.FargatePlatformVersion.LATEST, @@ -152,15 +153,66 @@ export class CommunityDashboardStack extends cdk.Stack { }, }); - service.connections.allowTo(fileSystem, ec2.Port.tcp(2049), "EFS access"); + grafanaService.connections.allowTo(fileSystem, ec2.Port.tcp(2049), "EFS access"); + + // ═════════════════════════════════════════════════════════════════════ + // 2. Metrics Task (on-demand + scheduled) — syncs data to EFS + // ═════════════════════════════════════════════════════════════════════ + const metricsTaskDef = new ecs.FargateTaskDefinition(this, "MetricsTaskDef", { + cpu: 512, + memoryLimitMiB: 1024, + }); + addEfsVolume(metricsTaskDef); - // ── API Gateway HTTP API + VPC Link ───────────────────────────────── - // No ALB needed — API Gateway connects directly to ECS via VPC Link. - // This avoids Epoxy/Riddler flagging a public-facing Grafana instance. + const metricsContainer = metricsTaskDef.addContainer("metrics", { + image: ecs.ContainerImage.fromAsset(path.join(__dirname, "../../"), { + file: "docker/Dockerfile.metrics", + platform: cdk.aws_ecr_assets.Platform.LINUX_AMD64, + }), + logging: ecs.LogDrivers.awsLogs({ + streamPrefix: "metrics-sync", + logRetention: logs.RetentionDays.TWO_WEEKS, + }), + secrets: { + GITHUB_TOKEN: ecs.Secret.fromSecretsManager(githubSecret), + }, + }); + + metricsContainer.addMountPoints({ + sourceVolume: "metrics-data", + containerPath: "/var/lib/grafana/data", + readOnly: false, + }); + + // Security group for the metrics task (needs EFS access) + const metricsSg = new ec2.SecurityGroup(this, "MetricsSg", { + vpc, + description: "Security group for metrics sync task", + allowAllOutbound: true, + }); + fileSystem.connections.allowFrom(metricsSg, ec2.Port.tcp(2049), "Metrics task EFS access"); + + // EventBridge scheduled rule: daily sync at 06:00 UTC + new events.Rule(this, "DailySyncRule", { + schedule: events.Schedule.cron({ hour: "6", minute: "0" }), + targets: [ + new targets.EcsTask({ + cluster, + taskDefinition: metricsTaskDef, + subnetSelection: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, + securityGroups: [metricsSg], + platformVersion: ecs.FargatePlatformVersion.LATEST, + }), + ], + }); + + // ═════════════════════════════════════════════════════════════════════ + // 3. API Gateway + CloudFront (unchanged) + // ═════════════════════════════════════════════════════════════════════ const vpcLink = new apigwv2.CfnVpcLink(this, "VpcLink", { name: "community-dashboard-vpc-link", subnetIds: vpc.privateSubnets.map((s) => s.subnetId), - securityGroupIds: [service.connections.securityGroups[0].securityGroupId], + securityGroupIds: [grafanaService.connections.securityGroups[0].securityGroupId], }); const httpApi = new apigwv2.CfnApi(this, "HttpApi", { @@ -169,14 +221,13 @@ export class CommunityDashboardStack extends cdk.Stack { description: "API Gateway for Community Dashboard (Grafana)", }); - // Integration: forward all requests to the Cloud Map service via VPC Link const integration = new apigwv2.CfnIntegration(this, "Integration", { apiId: httpApi.ref, integrationType: "HTTP_PROXY", integrationMethod: "ANY", connectionType: "VPC_LINK", connectionId: vpcLink.ref, - integrationUri: service.cloudMapService!.serviceArn, + integrationUri: grafanaService.cloudMapService!.serviceArn, payloadFormatVersion: "1.0", }); @@ -186,27 +237,56 @@ export class CommunityDashboardStack extends cdk.Stack { target: `integrations/${integration.ref}`, }); - const stage = new apigwv2.CfnStage(this, "DefaultStage", { + new apigwv2.CfnStage(this, "DefaultStage", { apiId: httpApi.ref, stageName: "$default", autoDeploy: true, }); - // Allow API Gateway VPC Link to reach the ECS service - service.connections.allowFrom( + grafanaService.connections.allowFrom( ec2.Peer.ipv4(vpc.vpcCidrBlock), ec2.Port.tcp(3000), "Allow API Gateway VPC Link" ); - // ── CloudFront ────────────────────────────────────────────────────── - // Extract the API Gateway domain from the endpoint URL const apiDomain = cdk.Fn.select( 2, cdk.Fn.split("/", httpApi.attrApiEndpoint) ); + // ── WAF rate-limit rule (protect against runaway CloudFront/API GW costs) + // Blocks any single IP exceeding 300 requests per 5-minute window. + // WAF for CloudFront must be in us-east-1, so we use a CfnWebACL directly. + const waf = new wafv2.CfnWebACL(this, "RateLimitAcl", { + scope: "CLOUDFRONT", + defaultAction: { allow: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: "CommunityDashboardWAF", + sampledRequestsEnabled: false, + }, + rules: [ + { + name: "RateLimitPerIP", + priority: 1, + action: { block: {} }, + visibilityConfig: { + cloudWatchMetricsEnabled: true, + metricName: "RateLimitPerIP", + sampledRequestsEnabled: false, + }, + statement: { + rateBasedStatement: { + limit: 300, + aggregateKeyType: "IP", + }, + }, + }, + ], + }); + const distribution = new cloudfront.Distribution(this, "Distribution", { + webAclId: waf.attrArn, defaultBehavior: { origin: new origins.HttpOrigin(apiDomain, { protocolPolicy: cloudfront.OriginProtocolPolicy.HTTPS_ONLY, @@ -239,10 +319,14 @@ export class CommunityDashboardStack extends cdk.Stack { description: "ECS cluster ARN", }); - new cdk.CfnOutput(this, "CreateSecretCommand", { - value: - 'aws secretsmanager create-secret --name strands-grafana/github-token --secret-string "ghp_xxx" --region us-east-1', - description: "Command to create the GitHub token secret (one-time)", + new cdk.CfnOutput(this, "MetricsTaskDefArn", { + value: metricsTaskDef.taskDefinitionArn, + description: "Metrics task definition ARN (for manual run-task)", + }); + + new cdk.CfnOutput(this, "RunMetricsSyncCommand", { + value: `aws ecs run-task --cluster ${cluster.clusterName} --task-definition ${metricsTaskDef.family} --launch-type FARGATE --network-configuration "awsvpcConfiguration={subnets=[${vpc.privateSubnets.map((s) => s.subnetId).join(",")}],securityGroups=[${metricsSg.securityGroupId}]}"`, + description: "Command to manually trigger a metrics sync", }); } } From 1e2b92910ed8c97a34c643819a1c3498a787448c Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Mon, 2 Mar 2026 10:47:32 -0500 Subject: [PATCH 22/22] docs: update AGENTS.md with split architecture and WAF rate-limiting --- community-dashboard/AGENTS.md | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/community-dashboard/AGENTS.md b/community-dashboard/AGENTS.md index bf96286..cf821c5 100644 --- a/community-dashboard/AGENTS.md +++ b/community-dashboard/AGENTS.md @@ -11,8 +11,9 @@ Compose or deploys to AWS with CDK (Fargate + EFS + CloudFront). - `strands-metrics/` — Rust CLI that syncs GitHub/PyPI/npm data into SQLite and computes daily aggregate metrics. -- `docker/` — Dockerfile (multi-stage: Rust build → Grafana image), - Compose file, entrypoint, and daily sync script. +- `docker/` — Split Dockerfiles (`Dockerfile.grafana` for serving, + `Dockerfile.metrics` for Rust build + sync), Compose file, + entrypoint, and daily sync script. - `provisioning/` — Grafana provisioning configs: datasource (SQLite) and seven dashboard JSON files in three folders. - `cdk/` — AWS CDK stack (TypeScript): VPC, ECS Fargate, EFS, @@ -139,8 +140,8 @@ npx tsc --noEmit | Module | Responsibility | |---|---| -| `main.rs` | CLI entry point (clap), dispatches subcommands | -| `client.rs` | GitHub API client via octocrab, GraphQL with retry/backoff | +| `main.rs` | CLI entry point (clap), dispatches subcommands, TTY-aware logging | +| `client.rs` | GitHub API client via octocrab, GraphQL with retry/backoff, dual progress (spinner + tracing) | | `db.rs` | SQLite schema init and migrations | | `downloads.rs` | PyPI / npm download stat fetching | | `goals.rs` | Goal thresholds and team member management | @@ -149,15 +150,21 @@ npx tsc --noEmit ### AWS deployment path ``` -CloudFront (HTTPS) +CloudFront (HTTPS, WAF rate-limit: 300 req/5min per IP) → API Gateway HTTP API (VPC Link) - → ECS Fargate (0.5 vCPU / 1 GB) - → Grafana + strands-metrics + → ECS Fargate — Grafana Service (always-on, 0.5 vCPU / 1 GB) → EFS (metrics.db, RETAIN policy) + +EventBridge (daily 06:00 UTC) + → ECS Fargate — Metrics Task (on-demand, 0.5 vCPU / 1 GB) + → EFS (writes metrics.db) + → Secrets Manager (GITHUB_TOKEN) ``` -Secrets Manager holds the GitHub PAT. Supercronic runs the daily -sync inside the container at 06:00 UTC. +The architecture splits serving from syncing: Grafana runs as an +always-on service, while the metrics sync runs as a scheduled +Fargate task triggered by EventBridge. WAF rate-limiting on +CloudFront prevents runaway costs from external traffic spikes. ## Testing Strategy @@ -188,10 +195,13 @@ and `read:project` scope for project items sync). (`GF_AUTH_ANONYMOUS_ENABLED=true`, `GF_AUTH_BASIC_ENABLED=false`). No login form, no sign-up. - EFS volume is encrypted at rest with `RETAIN` removal policy. -- Docker image is multi-stage; final image is based on - `grafana/grafana:latest` (Alpine). +- Docker images are split: `Dockerfile.grafana` is based on + `grafana/grafana:latest` (Alpine); `Dockerfile.metrics` is a + multi-stage Rust build → minimal Alpine runner. - SQLite datasource is mounted read-only in Grafana (`mode: ro` in `automatic.yaml`). +- WAF WebACL on CloudFront rate-limits to 300 requests per + 5-minute window per IP, preventing cost spikes from abuse. > TODO: No dependency scanning (e.g., `cargo audit`, Dependabot) > is configured. @@ -224,8 +234,6 @@ and `read:project` scope for project items sync). - Add team members via `team.yaml` and running `load-team`. - Environment variables: - `GITHUB_TOKEN` — required for sync/sweep commands. - - `RECOMPUTE_METRICS=true` — triggers full daily_metrics - recomputation on container startup. - `GF_*` — standard Grafana env var overrides. ## Further Reading