Öffentliches Register
Software-GesundheitsberichtSchema 0.27.0 · Metriken 1.13.0 · 2026-07-24 21:58 UTC

Ripixel-Studio / fitglue-server

FitGlue is a serverless fitness data aggregation and routing platform built on Google Cloud Platform. It ingests workout data from multiple sources (Hevy, Keiser, Fitbit), enriches it with standardized formats (FIT files), and routes it to connected services like Strava.

GoKeine Lizenz erkannt★ 1 Stern⑂ 0 Forksseit Jan. 2026Auf GitHub ansehen ↗

Ripixel-Studio/fitglue-server erreicht einen Gesundheitsindex von 56 von 100 und liegt damit im Bereich Mittel. Am stärksten schneidet es bei Vitality (85/100) ab, am schwächsten bei Community & Adoption (22/100). Zuletzt vor 1 Tag aktualisiert. Ein einzelner Mitwirkender trägt den Großteil der jüngsten Arbeit.

56
gesamt / 100
Mittel

Software-Gesundheitsindex

Metriken werden auf einer Skala von 1–100 in gewichtete Kategorien gruppiert. Der Gesamtwert beginnt als ihr Mittel; sobald öffentliche Evidenz die Richtlinie für Hochrisikojurisdiktionen auslöst, wird die Bewertung angepasst und erhält die Obergrenze 49 (Gefährdet). AI Readiness liegt außerhalb.

56
Exzellent85-100Vorbildlich; erfüllt im Wesentlichen alle geprüften Kriterien
Gut70-84Gesund; geringfügige Lücken
Mittel50-69Akzeptabel mit deutlichen Lücken; Überprüfung empfohlen
Gefährdet30-49Erhebliche Schwächen; eine Übernahme erfordert Vorsicht
Kritisch1-29Schwerwiegende Probleme (aufgegeben, nur ein Maintainer, keine Hygiene)
VitalitätCommunity &VerbreitungNachhaltigkeit &GovernanceEngineering-QualitätSicherheitAI Readiness

Bewertungsprofil

Jede Achse ist eine Kategorie. Die Form zählt mehr als der Durchschnitt — ein gesundes Projekt füllt die gesamte Fläche, während ein Profil aus Spitzen und Kratern bedeutet, dass Stärke in einer Dimension Risiken in einer anderen verdeckt.

Eigentümerschaft

Ripixel StudioOrganisation
0 Follower7 öffentliche Reposseit Juli 2026

Dieses Repository wird von einer Organisation getragen — geteilte, rechenschaftspflichtige Trägerschaft, die jeden einzelnen Maintainer überdauern kann.

Metriken nach Kategorie

Vitalität

Lebt das Projekt — wird Code geschrieben und werden Releases ausgeliefert?

85Exzellent · 22 % des Gesamtindex
Wie die Bewertung erfolgt
36/36Push-Aktualität — letzter Push vor 1 Tagen
18.7/36Commit-Rhythmus — 27/52 Wochen mit Commits
18/18Commit-Volumen — 1.250 Commits im letzten Jahr
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Verwendete Eingangsdaten
commits_last_year1.250
human_commit_share1
days_since_last_push1
active_weeks_last_year27
Wie die Bewertung erfolgt
16.2/27Liefert Releases aus — 100 Versions-Tags (keine GitHub-Releases)
36/36Release-Aktualität — letztes Release vor 1 Tagen
27/27Release-Rhythmus — ein Release etwa alle 0,6 Tage
0/10OpenSSF Scorecard: Signed-Releases — keine Daten
Verwendete Eingangsdaten
releases_count100
latest_release_tagv16.60.2
releases_from_tagsja
days_since_latest_release1
mean_days_between_releases0,6
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): OpenSSF Scorecard: Signed-Releases. Die verbleibenden Gewichte wurden renormalisiert.

Community & Verbreitung

Hat das Projekt Nutzer, Downloads, Aufmerksamkeit und ein einladendes Umfeld für Beitragende?

22Kritisch · 18 % des Gesamtindex
Wie die Bewertung erfolgt
0/60Stars — 1 Stars
0/25Forks — 0 Forks
0/15Watcher — 0 Watcher
Verwendete Eingangsdaten
forks0
stars1
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Wie die Bewertung erfolgt
22.5/22.5README
0/22.5Lizenz — keine Lizenzdatei erkannt
18/18CONTRIBUTING-Leitfaden
0/13.5Verhaltenskodex
0/7.2Issue-Vorlage
0/6.3PR-Vorlage
Verwendete Eingangsdaten
has_readmeja
has_licensenein
has_contributingja
has_issue_templatenein
has_code_of_conductnein
has_pull_request_templatenein

Nachhaltigkeit & Governance

Überdauert das Projekt die Menschen, die es tragen — Bus-Faktor, Reaktionsfähigkeit, Trägerschaft und Paketpflege?

44Gefährdet · 24 % des Gesamtindex
Wie die Bewertung erfolgt
9/54Bus-Faktor — 1 Beitragende decken die Hälfte aller Commits ab
0.1/22.5Commit-Verteilung — wichtigste beitragende Person verfasste 99 % der Commits
2.7/13.5Breite der Beitragenden — 2 Beitragende
3/10OpenSSF Scorecard: Contributors — project has 1 contributing companies or organizations -- score normalized to 3
Verwendete Eingangsdaten
bus_factor1
contributors_sampled2
top_contributor_share0,994
Wie die Bewertung erfolgt
46.8/46.8Issue-Lösungsquote — 100 % der Issues geschlossen
34.4/38.3PR-Annahme — 9/10 entschiedene PRs gemergt
4.5/15OpenSSF Scorecard: Code-Review — Found 9/27 approved changesets -- score normalized to 3
Verwendete Eingangsdaten
merged_prs9
open_issues0
closed_issues6
issue_closed_ratio1
closed_unmerged_prs1
Wie die Bewertung erfolgt
30/30Organisatorische Trägerschaft — im Besitz einer Organisation
0/20Verifizierte Domain
0/25Reichweite des Inhabers — 0 Follower von Ripixel-Studio
6.6/25Kontohistorie — 7 öffentliche Repos, Kontoalter ca. 0 Jahre
Verwendete Eingangsdaten
followers0
owner_typeOrganization
is_verified
owner_loginRipixel-Studio
public_repos7
account_age_days13

Engineering-Qualität

Sind grundlegende Engineering- und Dokumentationspraktiken vorhanden?

73Gut · 20 % des Gesamtindex
Wie die Bewertung erfolgt
24/24CI-Workflows — 1 Workflow(s)
24/24Tests vorhanden
0/16Linter-Konfiguration
0/9.6Pre-Commit-Hooks
0/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 9 out of 9 merged PRs checked by a CI test -- score normalized to 10
Verwendete Eingangsdaten
has_cija
has_testsja
has_editorconfignein
has_linter_confignein
has_precommit_confignein
Wie die Bewertung erfolgt
30/30README
25/25Dokumentationsverzeichnis
15/15Dokumentations-/Homepage-Site — https://fitglue.tech
10/10Repository-Beschreibung
0/10Topics
0/10Wiki
Verwendete Eingangsdaten
topics
has_wikinein
homepagehttps://fitglue.tech
has_readmeja
has_docs_dirja
has_descriptionja

Sicherheit

Sind die sichtbaren Sicherheits- und Lieferkettenpraktiken belastbar, ohne ungeklärte Exposition gegenüber Hochrisikojurisdiktionen?

53Mittel · 16 % des Gesamtindex
Wie die Bewertung erfolgt
6.8/7.5Binary-Artifacts — binaries present in source code
3.8/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 9 out of 9 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
2.2/7.5Code-Review — Found 9/27 approved changesets -- score normalized to 3
0.8/2.5Contributors — project has 1 contributing companies or organizations -- score normalized to 3
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
0/5Fuzzing — project is not fuzzed
0/2.5Lizenz — license file not detected
7.5/7.5Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — keine Daten
0.5/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 1
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — keine Daten
7.5/7.5Token-Permissions — GitHub workflow tokens follow principle of least privilege
0/7.5Vulnerabilities — 118 existing vulnerabilities detected
Verwendete Eingangsdaten
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate5,3
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): packaging, signed_releases. Die verbleibenden Gewichte wurden renormalisiert.

AI Readiness

Wie gut ist das Repository dafür ausgestattet, mit KI-Coding-Agenten entwickelt und gepflegt zu werden? Ein unabhängiges, experimentelles Badge — Gewicht 0,0, es wird eigenständig ausgewiesen und verändert den Gesamt-Gesundheitswert nicht.

75Gut · 0 % des Gesamtindex
Wie die Bewertung erfolgt
45/45Agentenanweisungen — CLAUDE.md
0/15Maschinenlesbare Doku (llms.txt)
40/40Lesbare Commit-Historie — 100 von 100 menschlichen Commits benennen ihre Absicht (strukturierter Betreff oder erläuternder Text)
Verwendete Eingangsdaten
has_llms_txtnein
legible_history_share1
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes14.943
Wie die Bewertung erfolgt
18/18Bootstrap mit einem Befehl — Makefile
22/22Automatisierte Tests
0/11Lint-/Format-Konfiguration
11/11Statische Typprüfung — src/typescript/parkrun-fetcher/tsconfig.json, tsconfig.json
10/10Reproduzierbare Umgebung — Dockerfile, lockfile
10/10Belegte Agentenpraxis — 38 der letzten 100 Commits von Agenten verfasst oder ihnen zugeschrieben
0/8Automatisierte Wartung — keine automatisierten Abhängigkeits-Updates beobachtet
1/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 1
Verwendete Eingangsdaten
has_nixnein
has_testsja
lockfilesgo.sum, package-lock.json
has_dockerfileja
typed_languageja
bootstrap_filesMakefile
has_devcontainernein
has_linter_confignein
typecheck_configssrc/typescript/parkrun-fetcher/tsconfig.json, tsconfig.json
agent_commit_share0,38
toolchain_manifestssrc/go/go.mod
dependency_bot_commit_share0
Wie die Bewertung erfolgt
45/45Typprüfbarer Code — Go (statisch typisiert)
53.2/55Handhabbare Dateigrößen — 20/600 Quelldateien über 60 KB
Verwendete Eingangsdaten
primary_languageGo
largest_source_bytes660.351
source_files_sampled600
oversized_source_files20
Wie die Bewertung erfolgt
40/40API-Schema (OpenAPI/GraphQL/proto) — src/openapi/fitbit/swagger.json, src/openapi/github/swagger.json, src/openapi/hevy/swagger.json, src/openapi/oura/swagger.json, src/openapi/polar/swagger.json, src/openapi/spotify/swagger.json, src/openapi/strava/swagger.json, src/openapi/trainingpeaks/swagger.json, src/openapi/wahoo/swagger.json, src/proto/gateway/admin.proto, src/proto/gateway/client.proto, src/proto/gateway/public.proto, src/proto/gateway/webhook.proto, src/proto/google/api/annotations.proto, src/proto/google/api/http.proto, src/proto/models/activity/enrichments.proto, src/proto/models/activity/roundup.proto, src/proto/models/activity/source.proto, src/proto/models/activity/standardized.proto, src/proto/models/activity/uploaded.proto, src/proto/models/events/pipeline.proto, src/proto/models/notification/notification.proto, src/proto/models/pipeline/config.proto, src/proto/models/pipeline/execution.proto, src/proto/models/pipeline/pending_input.proto, src/proto/models/plugin/manifest.proto, src/proto/models/plugin/provider.proto, src/proto/models/user/auth.proto, src/proto/models/user/billing.proto, src/proto/models/user/integration.proto, src/proto/models/user/profile.proto, src/proto/services/activity/activity.proto, src/proto/services/billing/billing.proto, src/proto/services/pipeline/pipeline.proto, src/proto/services/registry/registry.proto, src/proto/services/user/user.proto
0/20MCP-Server
0/40Lauffähige Beispiele
Verwendete Eingangsdaten
example_dirs
has_mcp_signalnein
api_schema_filessrc/openapi/fitbit/swagger.json, src/openapi/github/swagger.json, src/openapi/hevy/swagger.json, src/openapi/oura/swagger.json, src/openapi/polar/swagger.json, src/openapi/spotify/swagger.json, src/openapi/strava/swagger.json, src/openapi/trainingpeaks/swagger.json, src/openapi/wahoo/swagger.json, src/proto/gateway/admin.proto, src/proto/gateway/client.proto, src/proto/gateway/public.proto, src/proto/gateway/webhook.proto, src/proto/google/api/annotations.proto, src/proto/google/api/http.proto, src/proto/models/activity/enrichments.proto, src/proto/models/activity/roundup.proto, src/proto/models/activity/source.proto, src/proto/models/activity/standardized.proto, src/proto/models/activity/uploaded.proto, src/proto/models/events/pipeline.proto, src/proto/models/notification/notification.proto, src/proto/models/pipeline/config.proto, src/proto/models/pipeline/execution.proto, src/proto/models/pipeline/pending_input.proto, src/proto/models/plugin/manifest.proto, src/proto/models/plugin/provider.proto, src/proto/models/user/auth.proto, src/proto/models/user/billing.proto, src/proto/models/user/integration.proto, src/proto/models/user/profile.proto, src/proto/services/activity/activity.proto, src/proto/services/billing/billing.proto, src/proto/services/pipeline/pipeline.proto, src/proto/services/registry/registry.proto, src/proto/services/user/user.proto

Eckdaten

1GitHub-Sterne
2Mitwirkende
1.250Commits, letzte 12 Monate
1Tage seit letztem Push
100Releases
1Bus-Faktor
0offene Issues
npmPaket-Ökosysteme

Warnungen zur Datenerhebung

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • Could not fetch npm package 'fitglue-server' from its registry
  • Could not fetch go package 'github.com/fitglue/server/src/go' from its registry
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Weitere Details

OpenSSF Scorecard 5.3 / 10
5.3Gesamtwert

Unabhängige, werkzeugneutrale Sicherheitsbewertung durch das quelloffene OpenSSF Scorecard. Jede Prüfung honoriert eine Sicherheits-Praxis, nicht das Werkzeug eines bestimmten Anbieters. Prüfungen, die Scorecard nicht ermitteln konnte, sind mit k. A. markiert und vom Sicherheitswert ausgeschlossen (nie als null gezählt).Scorecard v5.5.0 · 2026-07-24 21:58 UTC

9Binary-Artifactsbinaries present in source code
5Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests9 out of 9 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
3Code-ReviewFound 9/27 approved changesets -- score normalized to 3
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
0Licenselicense file not detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
k. A.Packagingpackaging workflow not detected
1Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 1
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
k. A.Signed-Releasesno releases found
10Token-PermissionsGitHub workflow tokens follow principle of least privilege
0Vulnerabilities118 existing vulnerabilities detected
Direkte Abhängigkeiten 24
RegistryPaketVersionsvorgabeManifest
npmts-proto^2.8.3package.json
Gocloud.google.com/go/firestorev1.20.0src/go/go.mod
Gocloud.google.com/go/pubsubv1.50.1src/go/go.mod
Gocloud.google.com/go/storagev1.58.0src/go/go.mod
Gofirebase.google.com/go/v4v4.19.0src/go/go.mod
Gogithub.com/GoogleCloudPlatform/functions-framework-gov1.9.2src/go/go.mod
Gogithub.com/cloudevents/sdk-go/v2v2.16.2src/go/go.mod
Gogithub.com/cucumber/godogv0.15.1src/go/go.mod
Gogithub.com/getsentry/sentry-gov0.27.0src/go/go.mod
Gogithub.com/go-chi/chi/v5v5.2.5src/go/go.mod
Gogithub.com/google/generative-ai-gov0.20.1src/go/go.mod
Gogithub.com/google/uuidv1.6.0src/go/go.mod
Gogithub.com/muktihari/fitv0.26.1src/go/go.mod
Gogithub.com/oapi-codegen/runtimev1.1.2src/go/go.mod
Gogithub.com/stretchr/testifyv1.11.1src/go/go.mod
Gogithub.com/stripe/stripe-go/v76v76.25.0src/go/go.mod
Gogolang.org/x/netv0.50.0src/go/go.mod
Gogolang.org/x/oauth2v0.34.0src/go/go.mod
Gogolang.org/x/textv0.38.0src/go/go.mod
Gogoogle.golang.org/apiv0.262.0src/go/go.mod
Gogoogle.golang.org/genproto/googleapis/apiv0.0.0-20251202230838-ff82c1b0f217src/go/go.mod
Gogoogle.golang.org/grpcv1.78.0src/go/go.mod
Gogoogle.golang.org/protobufv1.36.11src/go/go.mod
Gogopkg.in/yaml.v3v3.0.1src/go/go.mod
Alle Abhängigkeiten nicht erhoben

Der aufgelöste Abhängigkeitssatz konnte für diesen Bericht nicht erhoben werden: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

JSON-Rohbericht maschinenlesbar
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 44614,
      "has_wiki": false,
      "homepage": "https://fitglue.tech",
      "languages": {
        "Go": 3761914,
        "HCL": 129688,
        "HTML": 55635,
        "Shell": 49987,
        "Python": 19181,
        "Gherkin": 807,
        "Makefile": 7887,
        "Dockerfile": 2311,
        "JavaScript": 10744,
        "TypeScript": 54401
      },
      "pushed_at": "2026-07-23T21:12:44Z",
      "created_at": "2026-01-16T15:55:24Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-23T21:12:48Z",
      "description": "FitGlue is a serverless fitness data aggregation and routing platform built on Google Cloud Platform. It ingests workout data from multiple sources (Hevy, Keiser, Fitbit), enriches it with standardized formats (FIT files), and routes it to connected services like Strava.",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": null,
      "default_branch": "main",
      "license_spdx_raw": null,
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": null,
      "name": "Ripixel Studio",
      "type": "Organization",
      "login": "Ripixel-Studio",
      "company": null,
      "location": null,
      "followers": 0,
      "avatar_url": "https://avatars.githubusercontent.com/u/302310591?v=4",
      "created_at": "2026-07-10T23:03:40Z",
      "is_verified": null,
      "public_repos": 7,
      "account_age_days": 13
    },
    "license": {
      "state": "absent",
      "spdx_id": null,
      "raw_spdx": null,
      "file_present": false,
      "scorecard_found": false,
      "profile_has_license": false
    },
    "activity": {
      "releases": [
        {
          "tag": "v16.60.2",
          "kind": "patch",
          "published_at": "2026-07-23T21:12:43Z"
        },
        {
          "tag": "v16.60.1",
          "kind": "patch",
          "published_at": "2026-07-22T08:47:11Z"
        },
        {
          "tag": "v16.60.0",
          "kind": "minor",
          "published_at": "2026-07-20T22:34:54Z"
        },
        {
          "tag": "v16.59.8",
          "kind": "patch",
          "published_at": "2026-07-20T13:05:29Z"
        },
        {
          "tag": "v16.59.7",
          "kind": "patch",
          "published_at": "2026-07-20T12:38:17Z"
        },
        {
          "tag": "v16.59.6",
          "kind": "patch",
          "published_at": "2026-07-20T10:25:56Z"
        },
        {
          "tag": "v16.59.5",
          "kind": "patch",
          "published_at": "2026-07-19T15:15:05Z"
        },
        {
          "tag": "v16.59.4",
          "kind": "patch",
          "published_at": "2026-07-18T23:59:13Z"
        },
        {
          "tag": "v16.59.3",
          "kind": "patch",
          "published_at": "2026-07-18T23:20:28Z"
        },
        {
          "tag": "v16.59.2",
          "kind": "patch",
          "published_at": "2026-07-18T14:22:02Z"
        },
        {
          "tag": "v16.59.1",
          "kind": "patch",
          "published_at": "2026-07-03T13:11:21Z"
        },
        {
          "tag": "v16.59.0",
          "kind": "minor",
          "published_at": "2026-07-01T22:04:01Z"
        },
        {
          "tag": "v16.58.1",
          "kind": "patch",
          "published_at": "2026-07-01T18:06:16Z"
        },
        {
          "tag": "v16.58.0",
          "kind": "minor",
          "published_at": "2026-06-22T21:21:58Z"
        },
        {
          "tag": "v16.57.4",
          "kind": "patch",
          "published_at": "2026-06-22T11:56:19Z"
        },
        {
          "tag": "v16.57.3",
          "kind": "patch",
          "published_at": "2026-06-20T16:25:19Z"
        },
        {
          "tag": "v16.57.2",
          "kind": "patch",
          "published_at": "2026-06-20T16:08:09Z"
        },
        {
          "tag": "v16.57.1",
          "kind": "patch",
          "published_at": "2026-06-19T09:32:16Z"
        },
        {
          "tag": "v16.57.0",
          "kind": "minor",
          "published_at": "2026-06-19T02:05:11Z"
        },
        {
          "tag": "v16.56.3",
          "kind": "patch",
          "published_at": "2026-06-19T01:26:25Z"
        },
        {
          "tag": "v16.56.2",
          "kind": "patch",
          "published_at": "2026-06-19T00:15:24Z"
        },
        {
          "tag": "v16.56.1",
          "kind": "patch",
          "published_at": "2026-06-18T20:15:01Z"
        },
        {
          "tag": "v16.56.0",
          "kind": "minor",
          "published_at": "2026-06-17T03:49:21Z"
        },
        {
          "tag": "v16.55.3",
          "kind": "patch",
          "published_at": "2026-06-17T01:22:58Z"
        },
        {
          "tag": "v16.55.2",
          "kind": "patch",
          "published_at": "2026-06-17T01:05:17Z"
        },
        {
          "tag": "v16.55.1",
          "kind": "patch",
          "published_at": "2026-06-17T00:57:02Z"
        },
        {
          "tag": "v16.55.0",
          "kind": "minor",
          "published_at": "2026-06-17T00:21:02Z"
        },
        {
          "tag": "v16.54.0",
          "kind": "minor",
          "published_at": "2026-06-16T23:57:32Z"
        },
        {
          "tag": "v16.53.0",
          "kind": "minor",
          "published_at": "2026-06-16T22:24:53Z"
        },
        {
          "tag": "v16.52.0",
          "kind": "minor",
          "published_at": "2026-06-16T16:12:15Z"
        },
        {
          "tag": "v16.51.0",
          "kind": "minor",
          "published_at": "2026-06-16T14:41:53Z"
        },
        {
          "tag": "v16.50.1",
          "kind": "patch",
          "published_at": "2026-06-16T06:29:47Z"
        },
        {
          "tag": "v16.50.0",
          "kind": "minor",
          "published_at": "2026-06-16T00:04:35Z"
        },
        {
          "tag": "v16.49.0",
          "kind": "minor",
          "published_at": "2026-06-15T23:48:54Z"
        },
        {
          "tag": "v16.48.0",
          "kind": "minor",
          "published_at": "2026-06-15T23:09:36Z"
        },
        {
          "tag": "v16.47.0",
          "kind": "minor",
          "published_at": "2026-06-15T22:28:32Z"
        },
        {
          "tag": "v16.46.0",
          "kind": "minor",
          "published_at": "2026-06-15T20:38:39Z"
        },
        {
          "tag": "v16.45.2",
          "kind": "patch",
          "published_at": "2026-06-15T17:06:11Z"
        },
        {
          "tag": "v16.45.1",
          "kind": "patch",
          "published_at": "2026-06-15T15:53:49Z"
        },
        {
          "tag": "v16.45.0",
          "kind": "minor",
          "published_at": "2026-06-15T10:13:27Z"
        },
        {
          "tag": "v16.44.1",
          "kind": "patch",
          "published_at": "2026-06-15T09:19:58Z"
        },
        {
          "tag": "v16.44.0",
          "kind": "minor",
          "published_at": "2026-06-14T16:03:37Z"
        },
        {
          "tag": "v16.43.2",
          "kind": "patch",
          "published_at": "2026-06-10T09:31:27Z"
        },
        {
          "tag": "v16.43.1",
          "kind": "patch",
          "published_at": "2026-06-10T00:35:53Z"
        },
        {
          "tag": "v16.43.0",
          "kind": "minor",
          "published_at": "2026-06-09T22:23:01Z"
        },
        {
          "tag": "v16.42.0",
          "kind": "minor",
          "published_at": "2026-06-09T21:46:08Z"
        },
        {
          "tag": "v16.41.0",
          "kind": "minor",
          "published_at": "2026-06-09T20:54:29Z"
        },
        {
          "tag": "v16.40.2",
          "kind": "patch",
          "published_at": "2026-06-09T20:29:20Z"
        },
        {
          "tag": "v16.40.1",
          "kind": "patch",
          "published_at": "2026-06-09T15:02:34Z"
        },
        {
          "tag": "v16.40.0",
          "kind": "minor",
          "published_at": "2026-06-09T10:18:24Z"
        },
        {
          "tag": "v16.39.0",
          "kind": "minor",
          "published_at": "2026-06-09T00:30:44Z"
        },
        {
          "tag": "v16.38.0",
          "kind": "minor",
          "published_at": "2026-06-08T22:45:09Z"
        },
        {
          "tag": "v16.37.1",
          "kind": "patch",
          "published_at": "2026-06-08T21:15:34Z"
        },
        {
          "tag": "v16.37.0",
          "kind": "minor",
          "published_at": "2026-06-06T20:24:12Z"
        },
        {
          "tag": "v16.36.1",
          "kind": "patch",
          "published_at": "2026-06-03T20:49:40Z"
        },
        {
          "tag": "v16.36.0",
          "kind": "minor",
          "published_at": "2026-06-03T00:58:12Z"
        },
        {
          "tag": "v16.35.4",
          "kind": "patch",
          "published_at": "2026-06-03T00:37:13Z"
        },
        {
          "tag": "v16.35.3",
          "kind": "patch",
          "published_at": "2026-06-02T23:59:37Z"
        },
        {
          "tag": "v16.35.2",
          "kind": "patch",
          "published_at": "2026-06-02T23:14:52Z"
        },
        {
          "tag": "v16.35.1",
          "kind": "patch",
          "published_at": "2026-06-02T22:13:49Z"
        },
        {
          "tag": "v16.35.0",
          "kind": "minor",
          "published_at": "2026-06-02T21:30:21Z"
        },
        {
          "tag": "v16.34.6",
          "kind": "patch",
          "published_at": "2026-06-02T16:16:58Z"
        },
        {
          "tag": "v16.34.5",
          "kind": "patch",
          "published_at": "2026-06-02T11:57:34Z"
        },
        {
          "tag": "v16.34.4",
          "kind": "patch",
          "published_at": "2026-06-02T08:36:43Z"
        },
        {
          "tag": "v16.34.3",
          "kind": "patch",
          "published_at": "2026-06-02T07:57:29Z"
        },
        {
          "tag": "v16.34.2",
          "kind": "patch",
          "published_at": "2026-06-01T23:44:14Z"
        },
        {
          "tag": "v16.34.1",
          "kind": "patch",
          "published_at": "2026-06-01T22:52:13Z"
        },
        {
          "tag": "v16.34.0",
          "kind": "minor",
          "published_at": "2026-06-01T15:05:28Z"
        },
        {
          "tag": "v16.33.0",
          "kind": "minor",
          "published_at": "2026-06-01T11:41:08Z"
        },
        {
          "tag": "v16.32.2",
          "kind": "patch",
          "published_at": "2026-05-31T20:55:37Z"
        },
        {
          "tag": "v16.32.1",
          "kind": "patch",
          "published_at": "2026-05-31T20:43:20Z"
        },
        {
          "tag": "v16.32.0",
          "kind": "minor",
          "published_at": "2026-05-31T20:24:12Z"
        },
        {
          "tag": "v16.31.0",
          "kind": "minor",
          "published_at": "2026-05-31T17:42:02Z"
        },
        {
          "tag": "v16.30.5",
          "kind": "patch",
          "published_at": "2026-05-31T14:27:27Z"
        },
        {
          "tag": "v16.30.4",
          "kind": "patch",
          "published_at": "2026-05-31T10:50:42Z"
        },
        {
          "tag": "v16.30.3",
          "kind": "patch",
          "published_at": "2026-05-31T10:37:17Z"
        },
        {
          "tag": "v16.30.2",
          "kind": "patch",
          "published_at": "2026-05-31T00:58:07Z"
        },
        {
          "tag": "v16.30.1",
          "kind": "patch",
          "published_at": "2026-05-31T00:31:49Z"
        },
        {
          "tag": "v16.30.0",
          "kind": "minor",
          "published_at": "2026-05-31T00:07:34Z"
        },
        {
          "tag": "v16.29.0",
          "kind": "minor",
          "published_at": "2026-05-30T20:22:41Z"
        },
        {
          "tag": "v16.28.0",
          "kind": "minor",
          "published_at": "2026-05-30T19:56:19Z"
        },
        {
          "tag": "v16.27.0",
          "kind": "minor",
          "published_at": "2026-05-30T15:08:26Z"
        },
        {
          "tag": "v16.26.0",
          "kind": "minor",
          "published_at": "2026-05-29T12:18:12Z"
        },
        {
          "tag": "v16.25.5",
          "kind": "patch",
          "published_at": "2026-05-29T12:04:34Z"
        },
        {
          "tag": "v16.25.4",
          "kind": "patch",
          "published_at": "2026-05-28T23:05:05Z"
        },
        {
          "tag": "v16.25.3",
          "kind": "patch",
          "published_at": "2026-05-28T21:45:42Z"
        },
        {
          "tag": "v16.25.2",
          "kind": "patch",
          "published_at": "2026-05-28T20:21:41Z"
        },
        {
          "tag": "v16.25.1",
          "kind": "patch",
          "published_at": "2026-05-28T19:10:16Z"
        },
        {
          "tag": "v16.25.0",
          "kind": "minor",
          "published_at": "2026-05-28T18:49:22Z"
        },
        {
          "tag": "v16.24.3",
          "kind": "patch",
          "published_at": "2026-05-28T15:46:51Z"
        },
        {
          "tag": "v16.24.2",
          "kind": "patch",
          "published_at": "2026-05-27T20:30:04Z"
        },
        {
          "tag": "v16.24.1",
          "kind": "patch",
          "published_at": "2026-05-27T20:05:33Z"
        },
        {
          "tag": "v16.24.0",
          "kind": "minor",
          "published_at": "2026-05-27T19:38:10Z"
        },
        {
          "tag": "v16.23.9",
          "kind": "patch",
          "published_at": "2026-05-27T18:22:33Z"
        },
        {
          "tag": "v16.23.8",
          "kind": "patch",
          "published_at": "2026-05-27T11:52:44Z"
        },
        {
          "tag": "v16.23.7",
          "kind": "patch",
          "published_at": "2026-05-27T00:17:27Z"
        },
        {
          "tag": "v16.23.6",
          "kind": "patch",
          "published_at": "2026-05-26T22:41:05Z"
        },
        {
          "tag": "v16.23.5",
          "kind": "patch",
          "published_at": "2026-05-26T22:05:38Z"
        },
        {
          "tag": "v16.23.4",
          "kind": "patch",
          "published_at": "2026-05-26T21:43:29Z"
        },
        {
          "tag": "v16.23.3",
          "kind": "patch",
          "published_at": "2026-05-26T19:43:07Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "892db28f78e90f9cf3052b6a3013092b69c45429",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.60.2 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-23T21:12:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e90b6130c3251f540bccb10f894b0883803f604a",
          "body": "…c (#16)\n\nShorten roundup \"Where it happened\" place chips to their leading locality (first comma component) and dedup on that short form, so verbose reverse-geocoded address blocks render concisely.\n\nCo-authored-by: Tom (Jarvis) <jarvis.ripixel@gmail.com>",
          "is_bot": false,
          "headline": "The locations we're displaying for \"Where it happened\" although corre…",
          "author_name": "tom-ripixel",
          "author_login": "tom-ripixel",
          "committed_at": "2026-07-23T20:57:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f6671922098f75fb19ac3e2a112f58b589b70840",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.60.1 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-22T08:47:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "01677f0a397a7d3e173d6bbe0ab02ac418549ce0",
          "body": "… (#15)\n\n* When a GPS-tracked activity happens, we should be able to extract the\n\nNow wire the real geocoder in production (`function.go`):\n\n* Fixed the red CircleCI build by correcting the half-wired automatic-location change (blank→named `location_naming` import and a stale test signature), and added HTTP-path tests to keep coverage above the 75% gate.\n\n---------\n\nCo-authored-by: Tom (Jarvis) <jarvis.ripixel@gmail.com>",
          "is_bot": false,
          "headline": "When a GPS-tracked activity happens, we should be able to extract the…",
          "author_name": "tom-ripixel",
          "author_login": "tom-ripixel",
          "committed_at": "2026-07-22T08:32:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "944e6d00ac18b0a0a5be498f28eb71c2afaacb55",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.60.0 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-20T22:34:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "55603990f6b57b2bd90e7a607362acd71eae71c1",
          "body": "* feat(firestore): persist pending-input source display metadata\n\nRound-trip SourceDisplayName, SourceActivityType, SourceStartTime and SourceActivitySource through the Firestore PendingInput converter, so the web can show which activity a pending input relates to (title/type/when/source) rather tha\n[…]\nde Opus 4.8 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Tom <tom@ripixel.studio>\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>\nCo-authored-by: Jay (Jarvis) <jarvis.ripixel@gmail.com>",
          "is_bot": false,
          "headline": "feat(firestore): persist pending-input source display metadata (#14)",
          "author_name": "tom-ripixel",
          "author_login": "tom-ripixel",
          "committed_at": "2026-07-20T22:21:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d24cdc3f73d8349022bcf7b28002d31a9e2fe83d",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.59.8 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-20T13:05:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c48c86af187357dc1aa535d86d538f75927395a4",
          "body": "…p (#13)\n\nAdded an observe-mode `renovate.json` to fitglue-server that labels blast-radius-SAFE updates (devDep patch/minor + GitHub Actions patch/digest) as `automerge-candidate` with a 3-day release-age hold while keeping all auto-merge off, and explicitly marks all runtime deps and majors `needs-human`, so auto-merge can later be enabled with a one-token edit.\n\nCo-authored-by: Tom (Jarvis) <jarvis.ripixel@gmail.com>",
          "is_bot": false,
          "headline": "```Add a renovate json to fitglue-server that classifies dependency u…",
          "author_name": "tom-ripixel",
          "author_login": "tom-ripixel",
          "committed_at": "2026-07-20T12:59:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b343856b8fa20b8a7dd831669747709279753f6f",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.59.7 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-20T12:38:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e8d0b48ae8e61d94be1a07a0a429e425d9f0e739",
          "body": "…e (#12)\n\nAdded a GitHub Actions PR gate (`.github/workflows/ci.yml`, job `build-lint-test`) that mirrors CircleCI's build/lint/test on the Go monorepo, installing from the lockfile and triggering on PRs to main.\n\nCo-authored-by: Tom (Jarvis) <jarvis.ripixel@gmail.com>",
          "is_bot": false,
          "headline": "```Add a GitHub Actions CI workflow to fitglue-server that runs on ev…",
          "author_name": "tom-ripixel",
          "author_login": "tom-ripixel",
          "committed_at": "2026-07-20T12:31:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "87eb9cd157832b702bbbb8427c9ec7ff83f4ce74",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.59.6 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-20T10:25:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dfa590b18935278c51ed66a85b4462300ed8d705",
          "body": "* The iCal title enricher is broken (server)\n\nAPI Error: 529 Overloaded. This is a server-side issue, usually temporary — try again in a moment. If it persists, check https://status.claude.com.\n\n* Fixed the iCal title enricher raising false \"calendar clash\" skips by suppressing a recurring event's original occurrence when a RECURRENCE-ID override (an edited single instance) replaces it.\n\n---------\n\nCo-authored-by: Tom (Jarvis) <jarvis.ripixel@gmail.com>",
          "is_bot": false,
          "headline": "The iCal title enricher is broken (server) (#11)",
          "author_name": "tom-ripixel",
          "author_login": "tom-ripixel",
          "committed_at": "2026-07-20T10:11:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "006a943cebb10f03668c29d8ebf2e3286fa8b068",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.59.5 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-19T15:15:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8a94ddffb035e48ab0f3cebead72af48e935ce15",
          "body": "…ty-to-show\n\nWe added functionality to show pending inputs related to a pipeline run on the pipeline run detail page, but I think if there are multiple then when we submit one, the others lose their reference somehow? Fix this.",
          "is_bot": false,
          "headline": "Merge pull request #10 from Ripixel-Studio/tom/9-we-added-functionali…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-07-19T15:00:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ae9976d2090383ece13d4a910f51f81038b03915",
          "body": "Fixed resolving one of multiple pending inputs orphaning the others by having SubmitInput fall back to the linked activity ID so a non-blocking input's resume reuses the original pipeline run instead of spawning a duplicate.\n\nCloses #9",
          "is_bot": false,
          "headline": "We added functionality to show pending inputs related to a pipeline ru",
          "author_name": "Tom (Jarvis)",
          "author_login": null,
          "committed_at": "2026-07-19T00:08:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5aa2e527311bf271bda9a927708780799b88cd99",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.59.4 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-18T23:59:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "07a63d41628fce93f9090605c4c79bbb2427fe3f",
          "body": "Make sure that when we \"Skip\" a non-blocking pending input, that it does not trigger the pipeline to run. It was non-blocking, so skipping it should be a no-op and the pipeline not run. It is still occuring no matter previous commits or deployments.",
          "is_bot": false,
          "headline": "Merge pull request #8 from Ripixel-Studio/tom/7-make-sure-that-when-we",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-07-18T23:44:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f6eadbaaa8082d6513c708e19807bf1e88c1e4aa",
          "body": "Persist the `non_blocking` flag on pending inputs in the Firestore converters so that skipping a non-blocking pending input no longer re-runs the pipeline.\n\nCloses #7",
          "is_bot": false,
          "headline": "Make sure that when we \"Skip\" a non-blocking pending input, that it do",
          "author_name": "Tom (Jarvis)",
          "author_login": null,
          "committed_at": "2026-07-18T23:42:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "445739b6a0b44362038903328cbe0412733f2120",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.59.3 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-18T23:20:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "703f7cf210e5c0769428554aa5b4da4fc213f131",
          "body": "…ided\n\nHang on - the user-provided description from when they uploaded the activity will never have a heading though and never should. Wrapping in start and end markers seems a very blunt solution.\n\nCan't we replace over what's there without losing the user",
          "is_bot": false,
          "headline": "Merge pull request #6 from Ripixel-Studio/tom/5-hang-on-the-user-prov…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-07-18T23:05:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0f59df9c1307813fd50cf4f55c62c79cec39c1eb",
          "body": "Cross-source description merge now replaces over the existing user text when the payload already contains it, instead of appending a duplicate copy — no markers needed.\n\nCloses #5",
          "is_bot": false,
          "headline": "Hang on - the user-provided description from when they uploaded the ac",
          "author_name": "Tom (Jarvis)",
          "author_login": null,
          "committed_at": "2026-07-18T23:01:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "878524caf81fa3d355f149994e5f17a0c042372e",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.59.2 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-18T14:22:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0c7ce40873571482888f7d4f99e9fd239f0115a6",
          "body": "…lue-web project\n\nThe GitHub org (and this repo along with the web repo) moved from FitGlue to\nRipixel-Studio, with the web repo also renamed web -> fitglue-web. The\ncreate-release job's \"Trigger Web Rebuild\" step still posted to the old\ngithub/FitGlue/web CircleCI project, which no longer exists un\n[…]\nGlue CircleCI org id to the new Ripixel-Studio org id, since OIDC tokens\nminted by CI now carry the new org's identity and were being rejected.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ci): point web-rebuild trigger at the renamed Ripixel-Studio/fitg…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-07-18T13:46:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8fd144746619bc9e2460e4b6d14d3532fe9a3c8e",
          "body": "…7 days\n\nShowcase activity JSON and FIT files were referenced from the ephemeral\npipeline artifacts bucket (payloads/, activities/*.fit), which has a 7-day\nlifecycle delete rule meant for short-lived execution records. Since\nShowcase pages are permanent and public, their backing blob would vanish\naf\n[…]\nhat same durable bucket instead of the ephemeral one.\nMissing-blob fetch failures are now logged at Error so this can't silently\nregress again.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(showcase): stop public showcases from losing activity data after …",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-07-17T14:42:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "99ae659a47b769829dcd048c68b58c48dee28966",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.59.1 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-03T13:11:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f67bf2515728791774296f61d17bce0f8018f40a",
          "body": "Strava, Intervals, TrainingPeaks and Hevy each reimplemented the same\ncross-source description merge: replace a matching section if one is\nconfigured, otherwise blindly append the whole payload description.\nMost enrichers (e.g. branding's \"Posted via FitGlue\" footer) don't\ndeclare a section header, \n[…]\nin \"Posted by\nFitGlue\".\n\nCentralize the merge logic into description.MergeDescription() and\nskip the append when the payload description is already present\nverbatim in the existing remote description.",
          "is_bot": false,
          "headline": "fix(destination): don't duplicate description on repeated Update() calls",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-07-03T12:53:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c48a5128e371e831d57d0ae9b9f1611bdf8ba34a",
          "body": "Resolving any pending input republishes the pipeline from the clean\npre-enrichment payload, so fitbit-heart-rate always re-ran and re-queried\nFitbit on every resume — even when a prior run already fetched the\ncorrect, complete stream. If that re-fetch raced Fitbit's own sync lag and\nexhausted retrie\n[…]\nay journal (previously only for name/tags/description/\nenrichments) to also persist and replay the heart rate stream, so a\nresume reuses the already-fetched data instead of re-querying the\nsource API.",
          "is_bot": false,
          "headline": "fix(pipeline): replay heart rate stream on resume instead of re-fetching",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-07-03T12:53:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dcb87267c3a534af9fa8767faf690055cb0f33a5",
          "body": "The re-run notification suppression relied on a stale isUpdate flag that\nwas only set for non-blocking pending-input resumes, missing same-source-\ndestination updates, blocking-resume refreshes of already-succeeded\ndestinations, and targeted reposts. Those cases re-sent the full \"Activity\nSynced\" no\n[…]\nication instead of being suppressed. Now derives suppression\ndirectly from whether the destination already had a SUCCESS outcome, and\nsends a lighter \"Activity Updated\" notice instead of full silence.",
          "is_bot": false,
          "headline": "fix(destination): correctly suppress/lighten notifications on re-runs",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-07-03T12:40:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8e575ae2a848895e145ac6435e339ebf0d30d738",
          "body": "…created_at\n\nAdminListPipelineRuns runs an unfiltered CollectionGroup(\"pipeline_runs\")\n.OrderBy(\"created_at\", Desc) query when no status/source filter is given.\nFirestore's automatic single-field indexes only cover COLLECTION scope, not\nCOLLECTION_GROUP, so this query has been failing with FailedPre\n[…]\nA prior\ncomment incorrectly assumed collection-group single-field indexes weren't\nneeded; corrected that assumption in both places it appeared.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(firestore): add missing collection-group index for pipeline_runs.…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-07-03T12:40:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ecf03e97ee3a18555fde4296d0c2e0704eb32a2b",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.59.0 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-01T22:04:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e8d3097273235806a0cad4ac648d210a8cb1700c",
          "body": "The showcase profile page's roundup band only ever fetched a fixed\nrecent-N via `limit`, so there was no way to page through older\nroundups. Replace `limit` with `page` on GetRecentPublicRoundups,\nreturning `total_pages`/`current_page` — mirroring the existing\nGetPublicShowcaseProfile activity-feed \n[…]\nups now paginates in-memory over the\n  full list with a fixed page size of 12, matching the profile entries\n  pagination approach.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(activity): add real pagination to recent public roundups",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-07-01T21:47:08Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "69069c556e672f52cb817d718c9b7169caffd46a",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.58.1 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-07-01T18:06:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "aced70780f39af79adfbc3b20ad1952c1466e791",
          "body": "Recent roundups on the showcase profile were ordered by period_start,\nwhich produces a confusing order when week/month/year roundups are mixed\n(a year roundup starts Jan 1 but covers through Dec 31, yet sorted below a\nDecember week). Order by period_end descending instead, so the roundup\ncovering the most recent dates surfaces first.\n\nUpdate the Firestore composite index (slug ASC, period_end DESC) to match.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(roundups): order showcase roundups by last date covered",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-07-01T17:45:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3d67adfefc8e510f85955ece4b65211f77746c17",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.58.0 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-22T21:21:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b04ef3911261c4ef1357bc9e8ece89b4e4545103",
          "body": null,
          "is_bot": false,
          "headline": "feat(cors): add public CORS middleware for unauthenticated API access",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-22T21:13:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "73253a5b09c6e74cdb153be86d09920a3e676258",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.57.4 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-22T11:56:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c086ebbfea5b91e1b2185002a601a211c714328d",
          "body": "hDrop includes a sentence like \"Here is your individual activity data:\"\nbefore the opening brace. Strip everything before the first '{' so users\ncan paste the raw export without editing it first.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(hdrop): strip leading prose before JSON object in export",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-22T11:40:45Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ac48ef2856f7cb68c6afb63704a08f2fff1b52b1",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.57.3 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-20T16:25:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "de2a320af0368b0d96d8cdfaf906f6abcfd244f0",
          "body": "…ate related logic",
          "is_bot": false,
          "headline": "refactor(pipeline): remove unused resume_only_enrichers field and upd…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-20T16:10:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c73592ce351893d467fd4c289901850b43d1c098",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.57.2 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-20T16:08:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "486a284c95c12fa32e332641bb36b4d426b9c325",
          "body": "Activities whose exercises map to no recognized muscle group (e.g.\nPilates) previously emitted the \"🔥 Muscle Heatmap:\" header with an\nempty body. Return an empty result in that case so the header-only\nblock is left out of the activity description.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(muscle-heatmap): skip section when no muscle groups have volume",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-20T15:52:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "891cb5505c4d2e5cf004ea951474ca019fe1832c",
          "body": "Strava (and other sources) deliver an entire run as a single lap, which\nhit calculateSplitsFromLaps' \">1100m\" branch and assigned the overall\naverage pace to every kilometre — so the Pace card showed e.g. 4:55/km\nfor all 10 splits. \"Best split\" was also taken from the fastest\ninstantaneous GPS speed\n[…]\ning splits. Lap division remains a fallback\nfor treadmill/structured workouts with no GPS stream. Best split is now the\nfastest real kilometre.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(pace-summary): derive real per-km splits from record stream",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-20T15:51:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "613515c68f518dccc2c8796cad5f7fc2930c735f",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.57.1 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-19T09:32:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3447aba653d9bcd6de03de270eb317e763298e8a",
          "body": "… pipeline config endpoints\n\nThree admin gaps reported from the console:\n\n- Pipeline runs had no user_id, so run-ops (repost/cancel/resolve) were disabled.\n  PipelineRun gains a user_id field; the cross-user admin listing derives it from\n  the run document's owning user (grandparent of the collectio\n[…]\n to the pipeline\n  service for any user; mutations audited).\n\nRegenerated gateway + client types. Tests cover the new handlers; coverage green.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(admin): populate run user_id, resolve identity from Firebase, add…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-19T09:16:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "37e06f611e264f17a1a2f0ade7679d72f87f9cbd",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.57.0 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-19T02:05:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1aa50f24b829be7f0489ea29d7ba965733a18e20",
          "body": "… and audit\n\nGrow the admin REST contract from a read-only list viewer into a full support\nsurface. New/changed RPCs on AdminGatewayService:\n\n- GetUser now returns an aggregated AdminUserDetail (profile + redacted\n  integration summaries + pipeline summaries + activity/run counts + pending\n  inputs \n[…]\ngateway types + OpenAPI spec. Unit tests cover the new handlers,\nRBAC guards, aggregation helpers and audit serialisation; coverage gate green.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(admin): expand admin gateway with 360° user detail, ops, billing…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-19T01:43:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "484d7e60249e4f5588c0a783b31109bd9276f492",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.56.3 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-19T01:26:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7f766009337a565460fc491295cc7c597cf87a33",
          "body": "… listing\n\nPlatform stats read user docs with the wrong field names/enum values\n(camelCase + \"ATHLETE\" short string) so Athletes, Syncs and the recent-\nexecutions block always reported zero. Read snake_case fields, match the\nfull UserTier enum name (tolerating legacy forms), compare created_at as an\n[…]\neys,\nand skip undecodable documents with a warning instead of failing the request.\nAccept camelCase query params from the generated client too.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(admin): correct platform stats and harden cross-user pipeline-run…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-19T01:11:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cf46ea3f1953236dfd190d02b9b563be68f3b3c3",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.56.2 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-19T00:15:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0a2cf79481d042dad96ad3254440aff5c88cd4f9",
          "body": "…uscle, auto-increment)",
          "is_bot": false,
          "headline": "test(server): cover pure enricher providers (pace, HR, hybrid race, m…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T23:58:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6bdee39ce68eb195a7eb942598754c79b1e32d95",
          "body": "…vy create/update validation",
          "is_bot": false,
          "headline": "test(server): cover sourceplugins HTTP paths, api-public handlers, he…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T23:47:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ba39d86e2fd8588ce550a0d777cca3f63b347f1e",
          "body": "…verage\n\ninternal/pipeline/enricher 66->83%, internal/pipeline 52->77%, internal/activity\n75->79%, api-public server 55->94%, plus oauth/personal_records/parkrun round 2.\nOverall 70.4% -> 74.2%.",
          "is_bot": false,
          "headline": "test(server): deepen pipeline/orchestrator/activity and api-public co…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T23:44:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b3efc4bd372bbf16e3a1f91ad1d980ab6ea09073",
          "body": "…th, webhook sources\n\ninternal/activity 39->75%, internal/pipeline/enricher 51->66%, internal/pipeline\n43->52%, oauth 25->49%, plus webhook source FetchActivity/parse paths.\nOverall 65.1% -> 70.4%.",
          "is_bot": false,
          "headline": "test(server): cover activity service RPCs, pipeline orchestrator, oau…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T22:45:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "87022f15ac54b0a8833e32b1fae25d55cec81bcb",
          "body": "…nfra\n\nAdds tests (test files only, no production changes) raising coverage in:\n- pkg/storage/firestore converters (~93%), pkg/domain/file_generators (~98%),\n  fit_parser (~85%), pkg/parkrun (~83%)\n- services/api-client (~80%), api-admin (~76%), destination executor (~79%),\n  destination uploaders, \n[…]\n distance_milestones,\n  goal_tracker, muscle_heatmap_image, location_naming, parkrun, ai_banner)\n\nOverall hand-written coverage 47.8% -> 65.1%.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(server): broad unit-test coverage across services, domain, and i…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T21:22:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2d35b8e8d50e0c246064c30a12fd6366bf87880a",
          "body": "…ty stores\n\ncheck-coverage.sh now excludes main.go entrypoints from the percentage too (not\njust the per-file floor), keeping the metric focused on unit-testable logic.\nAdds dead-Firestore smoke coverage across all internal/activity store methods.",
          "is_bot": false,
          "headline": "test(server): exclude main.go from coverage metric; smoke-test activi…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T21:08:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c31d6382a7ab40c73c6a4f7471b520ff420cdebb",
          "body": "…, mocks\n\nClears the remaining 0%-coverage files: photo_upload scaleToMax + skip paths,\nParkrunChecker constructor/handler, FCM empty-token early return, activity GCS\nblob delegation, and the shared test mock implementations.",
          "is_bot": false,
          "headline": "test(server): cover photo_upload, parkrun checker, fcm, activity blob…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T21:05:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "787ae6de2ca101df158d53015203bc6a53664fb0",
          "body": "… intervals source\n\nAdds coverage for the Sentry handler/capture helpers, the typed Firestore\ncollection accessors, SMTP/PubSub/database/billing/pipeline store constructors\nand error paths, the GCS blob URI validation, and the Intervals webhook parser.",
          "is_bot": false,
          "headline": "test(server): cover sentry, storage/firestore, infra clients, webhook…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T21:05:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "135e5a86a3f5c1a10f9647869471f4ab1df12a09",
          "body": "…oader",
          "is_bot": false,
          "headline": "test(server): cover strava webhook parser, intervals client, mock upl…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T21:05:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ce104000a4eb3765569231e13360f40a59a1870a",
          "body": "…mock uploader\n\n- internal/infra: logger, GCP handler options, component handler, gRPC logging\n  interceptor, HTTP logging middleware, GRPCDial, InitSentry.\n- pkg/infrastructure/oauth: Transport 401-retry/token-error paths, error-logging\n  transport, client constructor.\n- pkg/notificationpub: Enqueue publish + error.\n- destination mock uploader: Create/Update/Name.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(server): cover infra logging, oauth transport, notificationpub, …",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T21:05:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5287b0e52624762aa7a0b6924277dac1a400b757",
          "body": "…dlers\n\nMockable gRPC paths for AdminListPipelineRuns and user-data deletion, plus\nFirestore error-path coverage for stats and activity deletion via an\nunreachable emulator client.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(server): cover api-admin pipeline-runs, user-data, and stats han…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T21:05:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e6b719c23f9d7de734bda223fb11791131878e75",
          "body": "…plugins\n\n- pkg/domain/email: full coverage of layout + all notification templates.\n- pkg/domain/apikey: ingress key generation + hashing.\n- pkg/framework: TerminalError.\n- services/api-public: WriteJSON/WriteError gRPC-code mapping.\n- pkg/sourceplugins: registry lookup + not-configured error paths for all providers.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(server): cover email templates, apikey, framework errors, source…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T21:05:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2c3551922691e30c65d0914672b1a478f22ee72e",
          "body": "- api-client server: exercise library, showcase view stats, repost, FCM token,\n  activity stats handlers + NewAPIServer wiring; Firestore store constructors.\n- internal/activity: roundup period key/bounds, period-key parsing, export-job\n  map round-trip, toInt64, FIT-parse validation, export-trigger request parsing.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(server): cover api-client handlers and internal/activity pure logic",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T21:05:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fa59f5e5a978bfc7765e1064f220dae6189eb0cf",
          "body": "…vy tests\n\n- check-coverage.sh now strips generated (DO NOT EDIT) files from the metric,\n  raises the threshold to 75%, and adds a per-file floor (every hand-written\n  file except main.go entrypoints must have some coverage).\n- Add unit tests for distanceeffort, best_efforts, temperature_summary,\n  ai_activity_type, manual_workout_entry, mock, the providers registry/errors,\n  and the Hevy uploader mapper + template resolver.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(server): exclude generated code from coverage; add enricher + he…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T21:05:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d2bcc510ff4354f822bd467bff58921ada30d364",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.56.1 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-18T20:15:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a7824044e2d4250e64aec6955eaea2eb5137606f",
          "body": "…ents and replay key stripping",
          "is_bot": false,
          "headline": "test(enricher): add tests for non-idempotent provider's typed enrichm…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T20:00:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "514e1f4432b35597364a361e92dfc9f1842fdf68",
          "body": "…resume",
          "is_bot": false,
          "headline": "fix(enricher): restore and persist typed enrichments during pipeline …",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T19:58:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a781c5b9284f01dd1ea9b73be0edcd78ee840a10",
          "body": "A retry-destination / missed-destination Magic Action reuses the original\npipeline run. The executor's idempotency guard skips any destination that\nalready has a SUCCESS outcome on that run (\"Skipping already-uploaded\ndestination\"), so the targeted repost was a silent no-op: no new upload was\nmade a\n[…]\nFunc hook to the shared MockDatabase and a\nregression test asserting the guard skips a normal redelivery but is bypassed\nfor a targeted repost.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(destination): let targeted reposts bypass the already-uploaded guard",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T19:55:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cbf99a85814e63a64c8c1d8f7320b88bc589f69b",
          "body": "… failures\n\nTwo-layer fix:\n\n1. Code: non-retryable orchestrator errors now wrap in framework.TerminalError\n   so the CloudEvents wrapper ACKs the message instead of NACKing. The pipeline\n   run is already marked FAILED in Firestore — retrying is pointless and causes\n   the endless re-run behaviour s\n[…]\nletter) as a safety net for any error type that\n   slips past the code-level terminal handling. Also raise minimum_backoff\n   from 10s → 30s.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(pipeline): prevent infinite Pub/Sub retries on permanent enricher…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T19:42:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "32075e3bf33bc0d7ce38253226cd9e23c3759770",
          "body": "The router wrote updated_at via protojson.Format(timestamppb.Now()), which\nyields a quote-wrapped JSON string (\"2026-...Z\"). Firestore persisted that\nstring verbatim, and it then failed to decode back into the PipelineRun proto\n(\"invalid google.protobuf.Timestamp value\"). Any reader using decodeProt\n[…]\ncorrupt string as the final\nstate. Write timestamppb.Now() directly so the Firestore client stores a\nnative timestamp that round-trips cleanly.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(pipeline): store pipeline-run updated_at as a proto Timestamp",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T19:34:07Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b88ff4286087e7615d012ee8db4af780084f4a2b",
          "body": "Skipping a non-blocking pending input routed through SubmitInput, which\nrepublished the resume event and re-ran the whole pipeline. Non-blocking\ninputs never pause the pipeline, so destinations already ran on the first\npass — a data-less skip only triggered a no-op Update to every destination.\n\nShor\n[…]\ns with no input data: mark\nthe input complete and return without republishing. Blocking inputs still\nresume so the activity can finish syncing.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(pipeline): skip pipeline re-run when dismissing non-blocking input",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T19:33:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6e794828b8917a7a4f48f8c9195faa8a33ebab5d",
          "body": "Real hDrop exports have sweatRate and sodiumConcentration as JSON\nstrings, and timeseries sweatRate/fluidLoss as null during warm-up.\nFixes parse failure with: cannot unmarshal string into Go struct field\n.metadata.sweatRate of type float64.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(hdrop): handle string numeric fields and null timeseries values",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-18T19:20:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c2bf7e17c115d9def74e67ac7b46657a01aa1541",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.56.0 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-17T03:49:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "af80a28d41adb64c8b448f1e22d64ecb33e9705b",
          "body": "Adds a new \"location-pinner\" enricher that matches an activity by a title\nkeyword and attaches a real-world location for GPS-less workouts (gym\nclasses, home sessions). The pinned point is carried on a new transient\nStandardizedActivity.hint_location field — NOT written to records — so it\nfeeds the \n[…]\nn present\n- never overrides real GPS or an earlier enricher's location (force flag to override)\n- registry manifest entry + provider unit tests\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(enricher): add location-pinner to map titles to real places",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-17T03:28:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f0653f4896686392d7a6fae509aec164cfb68745",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.55.3 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-17T01:22:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "24dc6957048256150bde1c9a0738c345bb433285",
          "body": "…generation",
          "is_bot": false,
          "headline": "fix(roundup-ai): increase timeout and output token limit for summary …",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-17T01:09:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "adf96d66d8cc6fee6968ef6214a8945e52215491",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.55.2 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-17T01:05:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4407fd7d1982f67783a008be03122cde08af9ec1",
          "body": "Roundups show empty Best Efforts / Muscles / Places / Weather and zero\nElevation for any period whose showcase_profile_entry docs were created before\nthe enrichment-summary projection landed (commit f1cf530, 2026-06-16). Those\nfields are only projected at showcase time, so older entries lack them an\n[…]\ntion_name,\ncountry, temp_c, weather_description and elevation_gain_m back onto the entry.\nRoundups must then be recomputed to pick the data up.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(showcase): backfill enrichment summaries onto pre-existing entries",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-17T00:58:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2aae946679285d540253c9eb48be957b372d4df6",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.55.1 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-17T00:57:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "654714ebcf4ba76d417ab0494093cb9abf38039f",
          "body": "…nput resumes\n\nResolving two pending inputs at once created two Strava activities. Each\nresume published a fresh event that minted a new pipeline_execution_id, so\nthe per-execution idempotency guards couldn't see their sibling and both\nran Create.\n\nTwo-layer fix:\n\n- Resume now reuses the original pi\n[…]\ntinationCreate/ReleaseDestinationCreate to the Database\ninterface (Firestore impl + mocks) and wires the guard into the executor's\nCreate path.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(destination): prevent duplicate creates from concurrent pending-i…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-17T00:41:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "34b80b7c9e2d60071984e484dfd39f7cfcb29340",
          "body": "…y on resume\n\nPartial Fitbit HR pulls were being stretched to fill the whole session:\n\n- GPS path: the elastic alignment mapped each GPS point to a *relative*\n  position in the HR timeline, so a partial pull (e.g. first 20 min of a\n  60 min ride) was stretched across the entire track. Switch to abso\n[…]\nicher config and the enricher re-arms the data-lag retry on resume,\ngiving Fitbit time to finish syncing before committing to partial coverage.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(fitbit-hr): anchor HR to GPS by absolute time and re-arm lag retr…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-17T00:41:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "acb9579cdd48f3e4c3f05f4dbfa0276d5c439396",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.55.0 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-17T00:21:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "551f87f6458568257b7e49760fc211bdd41132ea",
          "body": "Tracks the showcase_id of the activity behind each \"ceiling raised\"\nhighlight — longest session, highest burn rate, peak avg HR, furthest,\nmost calories and heaviest volume — so the front-end can link each peak\nstraight to the session that set it. computeSessionPeaks now returns the\nsource ids alongside the values.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(roundup): record source session for each single-session peak",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-17T00:05:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1aaee3577cfcf3800bac43815ff657a8a478100c",
          "body": "…list\n\nA single pipeline_run with a malformed timestamp caused ListPipelineRuns to\nabort the entire page, which crashed the whole-account export worker (job\nmarked FAILED, UI showed an error). Skip records that fail to decode so one\ncorrupt row no longer breaks exports or activity listings.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(activity): skip undecodable pipeline runs instead of failing the …",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-17T00:05:44Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cdb653c6446d169662d099f16e12d989838d8165",
          "body": "The \"records broken\" callout linked to the first entry on the peak-PR\n*day* — wrong when that day had multiple sessions — and its \"in one\nsession\" count was actually per-day. Now PRs are attributed to the\nsession whose time window contains each record; the callout reports and\nlinks the session that set the most. When timestamps can't disambiguate,\nit degrades to the period aggregate with no link rather than a wrong one.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(roundup): attribute PR callout to the right session, not the day",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-16T23:57:57Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "571cbc15895cd15ad61766e6b8f8fa6e39968d03",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.54.0 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-16T23:57:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "afd17e3cf7d3b0e00c1771310f93e04a6ed58c91",
          "body": "Adds showcase_id to RoundupPhoto and RoundupRoute, populated in\ncollectRoundupMedia from the source entry, so the photo mosaic and route\nwall can link each item through to its activity.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(roundup): carry showcase_id on wall photos and routes",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-16T23:41:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7b6c62439f289d865d6bdf285902ab65a6f3f953",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.53.0 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-16T22:24:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b70cc7c18e52364843e972a4bb9c90b1326381eb",
          "body": "- Implemented ExportData RPC to enqueue asynchronous whole-account GDPR export jobs.\n- Added GetExportJob RPC to retrieve the current state of an export job.\n- Introduced ExportPipelineRun RPC for synchronous per-run ZIP generation.\n- Created Pub/Sub topic and subscription for handling data export t\n[…]\negration for managing export job records.\n- Updated API routes and client methods to support new export functionalities.\n- Enhanced notification system to inform users when their data export is ready.",
          "is_bot": false,
          "headline": "feat(activity): add data export functionality with job management",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-16T22:09:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a397220889d9c3615edb5b4f051c2f52772377dc",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.52.0 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-16T16:12:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a276786244f504e2ef4d590bd0596ea2476bca99",
          "body": "- Introduced GetShowcaseRoundupViewStats method in ClientGatewayService.\n- Updated ClientGatewayServiceClient and ClientGatewayServiceServer interfaces.\n- Implemented handler for GetShowcaseRoundupViewStats in APIServer.\n- Added ShowcaseId field to ShowcaseCalloutActivity for mapping to source showc\n[…]\nodified ListShowcaseViewStatsResponse to include roundups.\n- Updated API routes and protobuf definitions accordingly.\n- Adjusted Terraform configuration for environment variables related to enrichers.",
          "is_bot": false,
          "headline": "feat: add GetShowcaseRoundupViewStats RPC and related functionality",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-16T15:56:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b745d24d34a5721f33353245b54078bf1112765f",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.51.0 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-16T14:41:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1f42c5f622184856f016c667f8c5f0fb1b531c74",
          "body": "Adds owner-facing view/visitor analytics for public showcase surfaces\n(activity pages, profile, roundups) without storing raw IPs.\n\n- proto: RecordShowcaseView, GetShowcaseViewStats, ListShowcaseViewStats on\n  ActivityService; public fire-and-forget beacons on PublicGatewayService;\n  ShowcaseViewSta\n[…]\niew-salt secret, showcase_view_dedup TTL field,\n  api-public secret accessor + VIEW_SALT_SECRET env\n- regenerated pb.go stubs and OpenAPI specs\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(showcase): add privacy-preserving view & visitor metrics",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-16T14:21:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a9a0c754f311572ac3ecfa7b88b44ce2da623218",
          "body": "…nput updates\n\nResolving a non-blocking pending input triggers an update post to destinations.\nPreviously each resolution re-sent a PIPELINE_SUCCESS notification even though\nthe user was already notified at the initial sync. Thread a nonBlockingUpdate\nflag through UpdateStatus and suppress the succe\n[…]\non-blocking input remains (already prompted via PENDING_INPUT), so it should be\na \"Activity Synced\" notification, not a \"Partial Sync\" failure.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(destination): stop duplicate sync notifications on non-blocking i…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-16T14:21:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4f93f9514875d1a36c45bf39b78b05c091351283",
          "body": "…er doc is empty\n\nEmail notifications never sent because the notification service read the\nrecipient from users/{uid}.email, but that field is only ever written empty\nat creation (EmitUnpopulated) and never populated — profile.Email is set only\nin-memory in the admin ListUsers path. dispatchEmail th\n[…]\n active, to avoid an Auth\nround-trip on the common push-only path. Fixes all existing users with no\nbackfill. Adds unit tests for resolveEmail.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(notification): resolve recipient email from Firebase Auth when us…",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-16T14:17:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "962f8a94254ea2d8d4c23bb3de4a5de468e52888",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(roundup): mark Phase 5 polish (reel + 3D tilt) complete",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-16T14:01:22Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "313c87420e6b60f178911c44ec7ee0538bd9f1e9",
          "body": "The mobile app's notification handler navigates its embedded web view to\ndata[\"path\"], but the notification service never populated it, so push\nnotifications didn't deep-link on mobile at all.\n\nCompute an SPA-relative path (no /app prefix) per notification type in the\npush dispatch — pending input a\n[…]\ntivity/run detail page, connection actions to the connection, etc. Web\nclients are unaffected (they derive their own target from data[\"type\"]).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(notifications): emit deep-link path for mobile push navigation",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-16T13:48:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cc5b96df1d4567461b77373e7a7bbc80d1fbdbde",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.50.1 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-16T06:29:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7bed69f397ac6c7e1e68f9bee0c27b7743afa812",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(roundup): mark Phase 8 shareables v2 complete",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-16T06:20:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "658513e2393e200bccc6fc8d16e430c4ce5911bb",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): 16.50.0 [skip ci]",
          "author_name": "CircleCI Bot",
          "author_login": null,
          "committed_at": "2026-06-16T00:04:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f1cf530034ca5aa3c9647c9c8dd9c1af281c078f",
          "body": "Projects enrichment summaries onto each ShowcaseProfileEntry at creation\ntime (AddShowcaseEntry, from the GCS-hydrated ActivityEnrichments):\nelevation gain, location/country, weather, best efforts and primary\nmuscles (entry fields 21-27).\n\ngenerateRoundup then aggregates them into ShowcaseRoundup:\n-\n[…]\nes worked, by frequency\n\nData accrues forward — only activities synced after this ships carry the\nprojected summaries (no historical backfill).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(roundup): aggregate enrichment data for new roundup sections",
          "author_name": "James King",
          "author_login": "ripixel",
          "committed_at": "2026-06-15T23:49:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        }
      ],
      "releases_count": 100,
      "commits_last_year": 1250,
      "latest_release_at": "2026-07-23T21:12:43Z",
      "latest_release_tag": "v16.60.2",
      "releases_from_tags": true,
      "days_since_last_push": 1,
      "active_weeks_last_year": 27,
      "days_since_latest_release": 1,
      "mean_days_between_releases": 0.6
    },
    "community": {
      "has_readme": true,
      "has_license": false,
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 37,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": []
    },
    "popularity": {
      "forks": 0,
      "stars": 1,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": null,
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": true,
      "has_mcp_signal": false,
      "bootstrap_files": [
        "Makefile"
      ],
      "api_schema_files": [
        "src/openapi/fitbit/swagger.json",
        "src/openapi/github/swagger.json",
        "src/openapi/hevy/swagger.json",
        "src/openapi/oura/swagger.json",
        "src/openapi/polar/swagger.json",
        "src/openapi/spotify/swagger.json",
        "src/openapi/strava/swagger.json",
        "src/openapi/trainingpeaks/swagger.json",
        "src/openapi/wahoo/swagger.json",
        "src/proto/gateway/admin.proto",
        "src/proto/gateway/client.proto",
        "src/proto/gateway/public.proto",
        "src/proto/gateway/webhook.proto",
        "src/proto/google/api/annotations.proto",
        "src/proto/google/api/http.proto",
        "src/proto/models/activity/enrichments.proto",
        "src/proto/models/activity/roundup.proto",
        "src/proto/models/activity/source.proto",
        "src/proto/models/activity/standardized.proto",
        "src/proto/models/activity/uploaded.proto",
        "src/proto/models/events/pipeline.proto",
        "src/proto/models/notification/notification.proto",
        "src/proto/models/pipeline/config.proto",
        "src/proto/models/pipeline/execution.proto",
        "src/proto/models/pipeline/pending_input.proto",
        "src/proto/models/plugin/manifest.proto",
        "src/proto/models/plugin/provider.proto",
        "src/proto/models/user/auth.proto",
        "src/proto/models/user/billing.proto",
        "src/proto/models/user/integration.proto",
        "src/proto/models/user/profile.proto",
        "src/proto/services/activity/activity.proto",
        "src/proto/services/billing/billing.proto",
        "src/proto/services/pipeline/pipeline.proto",
        "src/proto/services/registry/registry.proto",
        "src/proto/services/user/user.proto"
      ],
      "has_devcontainer": false,
      "typecheck_configs": [
        "src/typescript/parkrun-fetcher/tsconfig.json",
        "tsconfig.json"
      ],
      "toolchain_manifests": [
        "src/go/go.mod"
      ],
      "largest_source_bytes": 660351,
      "source_files_sampled": 600,
      "oversized_source_files": 20,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 14943
    },
    "dependencies": {
      "manifests": [
        "package.json"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm"
      ],
      "dependencies": [
        {
          "name": "ts-proto",
          "manifest": "package.json",
          "ecosystem": "npm",
          "version_constraint": "^2.8.3"
        },
        {
          "name": "cloud.google.com/go/firestore",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.20.0"
        },
        {
          "name": "cloud.google.com/go/pubsub",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.50.1"
        },
        {
          "name": "cloud.google.com/go/storage",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.58.0"
        },
        {
          "name": "firebase.google.com/go/v4",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v4.19.0"
        },
        {
          "name": "github.com/GoogleCloudPlatform/functions-framework-go",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.9.2"
        },
        {
          "name": "github.com/cloudevents/sdk-go/v2",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.16.2"
        },
        {
          "name": "github.com/cucumber/godog",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.15.1"
        },
        {
          "name": "github.com/getsentry/sentry-go",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.27.0"
        },
        {
          "name": "github.com/go-chi/chi/v5",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v5.2.5"
        },
        {
          "name": "github.com/google/generative-ai-go",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.20.1"
        },
        {
          "name": "github.com/google/uuid",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.6.0"
        },
        {
          "name": "github.com/muktihari/fit",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.26.1"
        },
        {
          "name": "github.com/oapi-codegen/runtime",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.1.2"
        },
        {
          "name": "github.com/stretchr/testify",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.11.1"
        },
        {
          "name": "github.com/stripe/stripe-go/v76",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v76.25.0"
        },
        {
          "name": "golang.org/x/net",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.50.0"
        },
        {
          "name": "golang.org/x/oauth2",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.34.0"
        },
        {
          "name": "golang.org/x/text",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.38.0"
        },
        {
          "name": "google.golang.org/api",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.262.0"
        },
        {
          "name": "google.golang.org/genproto/googleapis/api",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.0.0-20251202230838-ff82c1b0f217"
        },
        {
          "name": "google.golang.org/grpc",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.78.0"
        },
        {
          "name": "google.golang.org/protobuf",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.36.11"
        },
        {
          "name": "gopkg.in/yaml.v3",
          "manifest": "src/go/go.mod",
          "ecosystem": "go",
          "version_constraint": "v3.0.1"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 9,
        "open_issues": 0,
        "closed_ratio": 1,
        "closed_issues": 6,
        "closed_unmerged_prs": 1
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "ripixel",
          "commits": 1010,
          "avatar_url": "https://avatars.githubusercontent.com/u/3977605?v=4"
        },
        {
          "type": "User",
          "login": "tom-ripixel",
          "commits": 6,
          "avatar_url": "https://avatars.githubusercontent.com/u/302311516?v=4"
        }
      ],
      "contributors_sampled": 2,
      "top_contributor_share": 0.994
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "go.sum",
        "package-lock.json"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 9,
            "reason": "binaries present in source code",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 5,
            "reason": "branch protection is not maximal on development and all release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "9 out of 9 merged PRs checked by a CI test -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 3,
            "reason": "Found 9/27 approved changesets -- score normalized to 3",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 3,
            "reason": "project has 1 contributing companies or organizations -- score normalized to 3",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 10,
            "reason": "update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 0,
            "reason": "license file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 1,
            "reason": "dependency not pinned by hash detected -- score normalized to 1",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 10,
            "reason": "GitHub workflow tokens follow principle of least privilege",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 0,
            "reason": "118 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "892db28f78e90f9cf3052b6a3013092b69c45429",
        "ran_at": "2026-07-24T21:58:35Z",
        "aggregate_score": 5.3,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-23T21:12:45Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-23T20:57:56Z",
      "ci_last_conclusion": null,
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/Ripixel-Studio/fitglue-server",
    "host": "github.com",
    "name": "fitglue-server",
    "owner": "Ripixel-Studio"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 56,
      "inputs": {
        "security": 53,
        "vitality": 85,
        "community": 22,
        "governance": 44,
        "engineering": 73
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "excellent",
        "name": "Vitality",
        "value": 85,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 83,
            "inputs": {
              "commits_last_year": 1250,
              "human_commit_share": 1,
              "days_since_last_push": 1,
              "active_weeks_last_year": 27
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 1 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 1
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "27/52 weeks with commits",
                "points": 18.7,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 27
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "1250 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 1250
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 88,
            "inputs": {
              "releases_count": 100,
              "latest_release_tag": "v16.60.2",
              "releases_from_tags": true,
              "days_since_latest_release": 1,
              "mean_days_between_releases": 0.6
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "100 version tags (no GitHub releases)",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "version_tags_no_releases",
                    "params": {
                      "count": 100
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 1 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 1
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~0.6 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 0.6
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 1,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 1 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 1
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 22,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "forks": 0,
              "stars": 1,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "1 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "at_risk",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 45,
            "inputs": {
              "has_readme": true,
              "has_license": false,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "no license file detected",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "license_absent",
                    "params": {}
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 18,
                "status": "met",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "at_risk",
        "name": "Sustainability & Governance",
        "value": 44,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 15,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 2,
              "top_contributor_share": 0.994
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 99% of commits",
                "points": 0.1,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 99
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "2 contributors",
                "points": 2.7,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "excellent",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 86,
            "inputs": {
              "merged_prs": 9,
              "open_issues": 0,
              "closed_issues": 6,
              "issue_closed_ratio": 1,
              "closed_unmerged_prs": 1
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "100% of issues closed",
                "points": 46.8,
                "status": "met",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "9/10 decided PRs merged",
                "points": 34.4,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 9,
                      "decided": 10
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 9/27 approved changesets -- score normalized to 3",
                "points": 4.5,
                "status": "partial",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 37,
            "inputs": {
              "followers": 0,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "Ripixel-Studio",
              "public_repos": 7,
              "account_age_days": 13
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "0 followers of Ripixel-Studio",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 0,
                      "login": "Ripixel-Studio"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "7 public repos, account ~0 yr old",
                "points": 6.6,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 7
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 0
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "good",
        "name": "Engineering Quality",
        "value": 73,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 68,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "1 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "9 out of 9 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 80,
            "inputs": {
              "topics": [],
              "has_wiki": false,
              "homepage": "https://fitglue.tech",
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": "https://fitglue.tech",
                "points": 15,
                "status": "met",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 53,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Packaging, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "packaging",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 53,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 5.3
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "binaries present in source code",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 3.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "9 out of 9 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 9/27 approved changesets -- score normalized to 3",
                "points": 2.2,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 0.8,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "update tool detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 1",
                "points": 0.5,
                "status": "partial",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "GitHub workflow tokens follow principle of least privilege",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "118 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 1
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "good",
        "name": "AI Readiness",
        "value": 75,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 14943
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "100 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 100,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "good",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 72,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum",
                "package-lock.json"
              ],
              "has_dockerfile": true,
              "typed_language": true,
              "bootstrap_files": [
                "Makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [
                "src/typescript/parkrun-fetcher/tsconfig.json",
                "tsconfig.json"
              ],
              "agent_commit_share": 0.38,
              "toolchain_manifests": [
                "src/go/go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "Makefile",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Makefile"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "src/typescript/parkrun-fetcher/tsconfig.json, tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "src/typescript/parkrun-fetcher/tsconfig.json, tsconfig.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "Dockerfile, lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Dockerfile, lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "38 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 38,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 1",
                "points": 1,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 98,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 660351,
              "source_files_sampled": 600,
              "oversized_source_files": 20
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Go (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "20/600 source files over 60KB",
                "points": 53.2,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 600,
                      "oversized": 20
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "at_risk",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "example_dirs": [],
              "has_mcp_signal": false,
              "api_schema_files": [
                "src/openapi/fitbit/swagger.json",
                "src/openapi/github/swagger.json",
                "src/openapi/hevy/swagger.json",
                "src/openapi/oura/swagger.json",
                "src/openapi/polar/swagger.json",
                "src/openapi/spotify/swagger.json",
                "src/openapi/strava/swagger.json",
                "src/openapi/trainingpeaks/swagger.json",
                "src/openapi/wahoo/swagger.json",
                "src/proto/gateway/admin.proto",
                "src/proto/gateway/client.proto",
                "src/proto/gateway/public.proto",
                "src/proto/gateway/webhook.proto",
                "src/proto/google/api/annotations.proto",
                "src/proto/google/api/http.proto",
                "src/proto/models/activity/enrichments.proto",
                "src/proto/models/activity/roundup.proto",
                "src/proto/models/activity/source.proto",
                "src/proto/models/activity/standardized.proto",
                "src/proto/models/activity/uploaded.proto",
                "src/proto/models/events/pipeline.proto",
                "src/proto/models/notification/notification.proto",
                "src/proto/models/pipeline/config.proto",
                "src/proto/models/pipeline/execution.proto",
                "src/proto/models/pipeline/pending_input.proto",
                "src/proto/models/plugin/manifest.proto",
                "src/proto/models/plugin/provider.proto",
                "src/proto/models/user/auth.proto",
                "src/proto/models/user/billing.proto",
                "src/proto/models/user/integration.proto",
                "src/proto/models/user/profile.proto",
                "src/proto/services/activity/activity.proto",
                "src/proto/services/billing/billing.proto",
                "src/proto/services/pipeline/pipeline.proto",
                "src/proto/services/registry/registry.proto",
                "src/proto/services/user/user.proto"
              ]
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": "src/openapi/fitbit/swagger.json, src/openapi/github/swagger.json, src/openapi/hevy/swagger.json, src/openapi/oura/swagger.json, src/openapi/polar/swagger.json, src/openapi/spotify/swagger.json, src/openapi/strava/swagger.json, src/openapi/trainingpeaks/swagger.json, src/openapi/wahoo/swagger.json, src/proto/gateway/admin.proto, src/proto/gateway/client.proto, src/proto/gateway/public.proto, src/proto/gateway/webhook.proto, src/proto/google/api/annotations.proto, src/proto/google/api/http.proto, src/proto/models/activity/enrichments.proto, src/proto/models/activity/roundup.proto, src/proto/models/activity/source.proto, src/proto/models/activity/standardized.proto, src/proto/models/activity/uploaded.proto, src/proto/models/events/pipeline.proto, src/proto/models/notification/notification.proto, src/proto/models/pipeline/config.proto, src/proto/models/pipeline/execution.proto, src/proto/models/pipeline/pending_input.proto, src/proto/models/plugin/manifest.proto, src/proto/models/plugin/provider.proto, src/proto/models/user/auth.proto, src/proto/models/user/billing.proto, src/proto/models/user/integration.proto, src/proto/models/user/profile.proto, src/proto/services/activity/activity.proto, src/proto/services/billing/billing.proto, src/proto/services/pipeline/pipeline.proto, src/proto/services/registry/registry.proto, src/proto/services/user/user.proto",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "src/openapi/fitbit/swagger.json, src/openapi/github/swagger.json, src/openapi/hevy/swagger.json, src/openapi/oura/swagger.json, src/openapi/polar/swagger.json, src/openapi/spotify/swagger.json, src/openapi/strava/swagger.json, src/openapi/trainingpeaks/swagger.json, src/openapi/wahoo/swagger.json, src/proto/gateway/admin.proto, src/proto/gateway/client.proto, src/proto/gateway/public.proto, src/proto/gateway/webhook.proto, src/proto/google/api/annotations.proto, src/proto/google/api/http.proto, src/proto/models/activity/enrichments.proto, src/proto/models/activity/roundup.proto, src/proto/models/activity/source.proto, src/proto/models/activity/standardized.proto, src/proto/models/activity/uploaded.proto, src/proto/models/events/pipeline.proto, src/proto/models/notification/notification.proto, src/proto/models/pipeline/config.proto, src/proto/models/pipeline/execution.proto, src/proto/models/pipeline/pending_input.proto, src/proto/models/plugin/manifest.proto, src/proto/models/plugin/provider.proto, src/proto/models/user/auth.proto, src/proto/models/user/billing.proto, src/proto/models/user/integration.proto, src/proto/models/user/profile.proto, src/proto/services/activity/activity.proto, src/proto/services/billing/billing.proto, src/proto/services/pipeline/pipeline.proto, src/proto/services/registry/registry.proto, src/proto/services/user/user.proto"
                    }
                  }
                ],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "Could not fetch npm package 'fitglue-server' from its registry",
    "Could not fetch go package 'github.com/fitglue/server/src/go' from its registry",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-24T21:58:47.485904Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/r/Ripixel-Studio/fitglue-server.svg",
  "full_name": "Ripixel-Studio/fitglue-server",
  "license_state": "absent",
  "license_spdx": null
}

Bewertungen sind Signale, keine Garantien. Sie spiegeln öffentlich sichtbare Praxis auf GitHub wider — kein Code-Audit und keine Sicherheitsgarantie.

Fehlende Daten werden ausgeschlossen und die Gewichte neu normiert, nie als null bewertet. Die Methodik ist versioniert und offen: Metriken v1.13.0, Schema v0.27.0 — vollständige Methodik · Metriken-Wiki.

Wie ein einzelnes Ergebnis im Gesamtregister steht: aggregierte Statistiken.