diff --git a/.github/workflows/community-dashboard.yaml b/.github/workflows/community-dashboard.yaml new file mode 100644 index 0000000..8e6b19b --- /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/strands-metrics + +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/strands-metrics/target + key: ${{ runner.os }}-cargo-${{ hashFiles('community-dashboard/strands-metrics/Cargo.lock') }} + 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 + + - name: Load Team Configuration + run: cargo run --release -- load-team + + - 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..78b8f97 --- /dev/null +++ b/community-dashboard/.gitignore @@ -0,0 +1,16 @@ +metrics.db +strands-metrics/target/ + +# CDK +cdk/node_modules/ +cdk/cdk.out/ +cdk/dist/ +cdk/.env + +# Docker (ignore DB snapshots but keep the directory) +docker/data/* +!docker/data/.gitkeep + +# IDE +.idea/ +.DS_Store diff --git a/community-dashboard/README.md b/community-dashboard/README.md new file mode 100644 index 0000000..8afba8d --- /dev/null +++ b/community-dashboard/README.md @@ -0,0 +1,276 @@ +# 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/ +├── 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/ +│ ├── Dockerfile # Unified Grafana + metrics-sync image +│ ├── docker-compose.local.yaml # Local dev with auto-sync +│ ├── entrypoint.sh # Container startup script +│ └── sync-all.sh # Full sync pipeline (used by cron) +├── 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 dev with auto-sync (Docker) + +Build the unified image that syncs GitHub data automatically: + +```bash +GITHUB_TOKEN=ghp_xxx docker compose -f docker/docker-compose.local.yaml up --build +``` + +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: + +```bash +cd strands-metrics + +# 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 + +# Load team members for the Team dashboard +cargo run --release -- load-team + +# 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" +``` + +## 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 (default: `../goals.yaml`) | +| `list-goals` | Display all configured goal thresholds | +| `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) | + +### 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/Dockerfile b/community-dashboard/docker/Dockerfile new file mode 100644 index 0000000..e4a32bd --- /dev/null +++ b/community-dashboard/docker/Dockerfile @@ -0,0 +1,71 @@ +# ============================================================================= +# 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 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 + +# ============================================================================= +# 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 and sync scripts +COPY docker/entrypoint.sh /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 + +# 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 +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/data/.gitkeep b/community-dashboard/docker/data/.gitkeep new file mode 100644 index 0000000..e69de29 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..ecfffcb --- /dev/null +++ b/community-dashboard/docker/entrypoint.sh @@ -0,0 +1,64 @@ +#!/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 ───────────────────────────────────────────────────── +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 * * * sync-all.sh >> /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/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/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..c3c6be5 --- /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: /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/strands-metrics/Cargo.toml b/community-dashboard/strands-metrics/Cargo.toml new file mode 100644 index 0000000..1e4f51b --- /dev/null +++ b/community-dashboard/strands-metrics/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/strands-metrics/src/aggregates.rs b/community-dashboard/strands-metrics/src/aggregates.rs new file mode 100644 index 0000000..5f01afb --- /dev/null +++ b/community-dashboard/strands-metrics/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/strands-metrics/src/client.rs b/community-dashboard/strands-metrics/src/client.rs new file mode 100644 index 0000000..fe39d58 --- /dev/null +++ b/community-dashboard/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/community-dashboard/strands-metrics/src/db.rs b/community-dashboard/strands-metrics/src/db.rs new file mode 100644 index 0000000..c150b98 --- /dev/null +++ b/community-dashboard/strands-metrics/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/strands-metrics/src/downloads.rs b/community-dashboard/strands-metrics/src/downloads.rs new file mode 100644 index 0000000..f89ea35 --- /dev/null +++ b/community-dashboard/strands-metrics/src/downloads.rs @@ -0,0 +1,233 @@ +use anyhow::{Context, Result}; +use chrono::{Duration, Utc}; +use rusqlite::{params, Connection}; +use serde::Deserialize; + +// ============================================================================ +// PyPI API Types +// ============================================================================ + +#[derive(Debug, Deserialize)] +struct PyPIStatsResponse { + data: Vec, +} + +#[derive(Debug, Deserialize)] +struct PyPIDataPoint { + date: String, + downloads: i64, +} + +// ============================================================================ +// npm API Types +// ============================================================================ + +#[derive(Debug, Deserialize)] +struct NpmRangeResponse { + downloads: Vec, +} + +#[derive(Debug, Deserialize)] +struct NpmDownloadPoint { + day: String, + downloads: i64, +} + +// ============================================================================ +// 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) +} + diff --git a/community-dashboard/strands-metrics/src/goals.rs b/community-dashboard/strands-metrics/src/goals.rs new file mode 100644 index 0000000..94995da --- /dev/null +++ b/community-dashboard/strands-metrics/src/goals.rs @@ -0,0 +1,391 @@ +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", + } + } + + #[cfg(test)] + 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 + #[cfg(test)] + 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/strands-metrics/src/main.rs b/community-dashboard/strands-metrics/src/main.rs new file mode 100644 index 0000000..36b4d1e --- /dev/null +++ b/community-dashboard/strands-metrics/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} | Warning Ratio", + "Metric", "Value", "Label", "Direction" + ); + 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