Registro público
Informe de salud del softwareesquema 0.26.0 · métricas 1.13.0 · 2026-07-22 11:02 UTC

Yolean / y-cluster

Go · ShellSin licencia detectada★ 0 estrellas⑂ 0 forksdesde abr 2026Ver en GitHub ↗

Yolean/y-cluster tiene un índice de salud de 50 sobre 100, lo que lo sitúa en la banda Moderado. Su puntuación más alta es Vitality (73/100) y la más baja, Community & Adoption (12/100). Se actualizó por última vez hace 8 días. Una sola persona concentra la mayor parte del trabajo reciente.

50
global / 100
Moderado

Índice de salud del software

Las métricas se agrupan en categorías ponderadas sobre una escala de 1 a 100. El resultado global parte de su media; cuando la evidencia pública activa la Política de Jurisdicciones de Alto Riesgo, la calificación se ajusta y recibe el límite 49 (En riesgo). Preparación para IA queda fuera.

50
Excelente85-100Ejemplar; cumple prácticamente todos los criterios evaluados
Bueno70-84Saludable; carencias menores
Moderado50-69Aceptable con carencias notables; se recomienda revisión
En riesgo30-49Debilidades significativas; su adopción exige cautela
Crítico1-29Problemas graves (proyecto abandonado, un solo mantenedor, sin higiene)
VitalidadComunidad yAdopciónSostenibilidady GobernanzaCalidad deIngenieríaSeguridadPreparaciónpara IA

Perfil de puntuación

Cada eje es una categoría. La forma importa más que la media: un proyecto sano llena toda la figura, mientras que un perfil de picos y cráteres indica que la fortaleza en una dimensión enmascara el riesgo en otra.

Titularidad

YoleanOrganización
9 seguidores99 repositorios públicosdesde feb 2015

Este repositorio está respaldado por una organización: una custodia compartida y responsable que puede sobrevivir a cualquier mantenedor individual.

Ecosistemas de paquetes

RegistroPaqueteVersiónDescargas / mesVersionesÚltima publicación
Gogithub.com/Yolean/y-clusterv0.5.0-20hace 8 días

Métricas por categoría

Vitalidad

¿Está vivo el proyecto: se escribe código y se publican versiones?

73Bueno · 22% del índice global
Cómo se puntúa
28.8/36Recencia de push — último push hace 8 días
4.2/36Cadencia de commits — 6/52 semanas con commits
18/18Volumen de commits — 181 commits en el último año
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Datos de entrada utilizados
commits_last_year181
human_commit_share1
days_since_last_push8
active_weeks_last_year6
Cómo se puntúa
27/27Publica versiones — 20 versiones publicadas
36/36Recencia de las versiones — última versión hace 8 días
27/27Cadencia de publicación — una versión cada ~7,8 días
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Datos de entrada utilizados
releases_count20
latest_release_tagv0.5.0
releases_from_tagsno
days_since_latest_release8
mean_days_between_releases7,8

Comunidad y Adopción

¿Tiene el proyecto usuarios, descargas, atención y unas condiciones acogedoras para quienes contribuyen?

12Crítico · 18% del índice global
Cómo se puntúa
0/60Estrellas — 0 estrellas
0/25Forks — 0 forks
0/15Observadores — 0 observadores
Datos de entrada utilizados
forks0
stars0
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
0/22.5Licencia — no se detectó ningún archivo de licencia
0/18Guía CONTRIBUTING
0/13.5Código de conducta
0/7.2Plantilla de issues
0/6.3Plantilla de PR
Datos de entrada utilizados
has_readme
has_licenseno
has_contributingno
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno

Sostenibilidad y Gobernanza

¿Sobrevivirá el proyecto a sus personas: factor bus, capacidad de respuesta, quién lo respalda y mantenimiento del paquete?

51Moderado · 24% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
0/22.5Distribución de commits — el principal contribuyente firma el 100% de los commits
1.4/13.5Amplitud de contribuyentes — 1 contribuyentes
0/10OpenSSF Scorecard: Contributors — project has 0 contributing companies or organizations -- score normalized to 0
Datos de entrada utilizados
bus_factor1
contributors_sampled1
top_contributor_share1
Cómo se puntúa
15.6/46.8Resolución de issues — 33% de issues cerradas
35.4/38.3Aceptación de PR — 25/27 PR decididos fusionados
0/15OpenSSF Scorecard: Code-Review — Found 0/1 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs25
open_issues2
closed_issues1
issue_closed_ratio0,333
closed_unmerged_prs2
Cómo se puntúa
30/30Respaldo de la propiedad — propiedad de una organización
0/20Dominio verificado
7.2/25Alcance del propietario — 9 seguidores de Yolean
25/25Trayectoria — 99 repos públicos, cuenta de ~11 años
Datos de entrada utilizados
followers9
owner_typeOrganization
is_verified
owner_loginYolean
public_repos99
account_age_days4165
Cómo se puntúa
25/25Publicado y resoluble — 1 paquete(s) en go
35/35Recencia de publicación — última publicación hace 8 días
20/20Historial de versiones — 20 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packagesgithub.com/Yolean/y-cluster
ecosystemsgo
any_deprecatedno
min_days_since_publish8

Calidad de Ingeniería

¿Existen unas prácticas mínimas de ingeniería y documentación?

66Moderado · 20% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 3 flujo(s) de trabajo
24/24Pruebas presentes
16/16Configuración de linter — .golangci.yaml
0/9.6Hooks de pre-commit
0/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 1 out of 1 merged PRs checked by a CI test -- score normalized to 10
Datos de entrada utilizados
has_ci
has_tests
has_editorconfigno
has_linter_config
has_precommit_configno

Documentación

40En riesgo
Cómo se puntúa
30/30README
0/25Directorio de documentación
0/15Sitio de documentación / página del proyecto
0/10Descripción del repositorio
0/10Topics
10/10Wiki
Datos de entrada utilizados
topics
has_wiki
homepage
has_readme
has_docs_dirno
has_descriptionno

Seguridad

¿Son sólidas las prácticas visibles de seguridad y de cadena de suministro, sin exposición jurisdiccional de alto riesgo sin resolver?

38En riesgo · 16% del índice global
Cómo se puntúa
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
2.5/2.5CI-Tests — 1 out of 1 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
0/7.5Code-Review — Found 0/1 approved changesets -- score normalized to 0
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
0/2.5Licencia — 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 — sin datos
5/5Pinned-Dependencies — all dependencies are pinned
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 — Project has not signed or included provenance with any releases.
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
6/7.5Vulnerabilities — 2 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate3,9
Excluidos de la puntuación (sin datos o no aplicable): packaging. Los pesos restantes se han renormalizado.

Preparación para IA

¿Hasta qué punto está el repositorio preparado para desarrollarse y mantenerse con agentes de codificación de IA? Es una insignia independiente y experimental — peso 0,0, de modo que se presenta por separado y no afecta a la puntuación de salud global.

68Moderado · 0% del índice global
Cómo se puntúa
0/45Instrucciones para agentes — sin CLAUDE.md / AGENTS.md / reglas de editor
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 93 de 100 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share0,93
agent_instruction_files
agent_instruction_max_bytes
Cómo se puntúa
12.6/18Arranque con un solo comando — go.mod (convención del toolchain, sin ejecutor de tareas)
22/22Pruebas automatizadas
11/11Configuración de lint / formato — .golangci.yaml
11/11Verificación estática de tipos — Go (tipado estático)
10/10Entorno reproducible — lockfile
10/10Práctica demostrada con agentes — 77 de los últimos 100 commits con autoría o crédito de agente
0/8Mantenimiento automatizado — no se observan actualizaciones automáticas de dependencias
10/10OpenSSF Scorecard: Pinned-Dependencies — all dependencies are pinned
Datos de entrada utilizados
has_nixno
has_tests
lockfilesgo.sum
has_dockerfileno
typed_language
bootstrap_files
has_devcontainerno
has_linter_config
typecheck_configs
agent_commit_share0,77
toolchain_manifestsgo.mod
dependency_bot_commit_share0
Cómo se puntúa
45/45Código verificable por tipos — Go (tipado estático)
55/55Tamaños de archivo manejables — 0/211 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageGo
largest_source_bytes40.587
source_files_sampled211
oversized_source_files0
Cómo se puntúa
0/40Esquema de API (OpenAPI/GraphQL/proto)
0/20Servidor MCP
40/40Ejemplos ejecutables — example
Datos de entrada utilizados
example_dirsexample
has_mcp_signalno
api_schema_files

Datos clave

0estrellas de GitHub
1contribuidores
181commits en los últimos 12 meses
8días desde el último push
20versiones publicadas
1factor bus
2issues abiertas
Goecosistemas de paquetes

Advertencias de recopilación de datos

  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Más detalle

OpenSSF Scorecard 3.9 / 10
3.9agregado

Evaluación de seguridad independiente y agnóstica en cuanto a herramientas, procedente del proyecto de código abierto OpenSSF Scorecard. Cada comprobación premia una práctica de seguridad, no la herramienta de un proveedor concreto. Las comprobaciones que Scorecard no pudo determinar se marcan como n/d y se excluyen de la puntuación de seguridad (nunca se cuentan como cero).Scorecard v5.5.0 · 2026-07-22 11:02 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
10CI-Tests1 out of 1 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/1 approved changesets -- score normalized to 0
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update 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
n/dPackagingpackaging workflow not detected
10Pinned-Dependenciesall dependencies are pinned
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
8Vulnerabilities2 existing vulnerabilities detected
Dependencias directas 14
RegistroPaqueteRestricción de versiónManifiesto
Gocuelang.org/gov0.16.1go.mod
Gogithub.com/containerd/errdefsv1.0.0go.mod
Gogithub.com/google/go-containerregistryv0.21.5go.mod
Gogithub.com/hetznercloud/hcloud-go/v2v2.39.0go.mod
Gogithub.com/invopop/jsonschemav0.14.0go.mod
Gogithub.com/moby/moby/apiv1.54.2go.mod
Gogithub.com/moby/moby/clientv0.4.1go.mod
Gogithub.com/pkg/sftpv1.13.10go.mod
Gogithub.com/spf13/cobrav1.10.2go.mod
Gogo.uber.org/zapv1.27.1go.mod
Gogolang.org/x/cryptov0.54.0go.mod
Gosigs.k8s.io/kustomize/apiv0.21.1go.mod
Gosigs.k8s.io/kustomize/kyamlv0.21.1go.mod
Gosigs.k8s.io/yamlv1.6.0go.mod
Todas las dependencias no recopilado

No fue posible recopilar el conjunto de dependencias resuelto para este informe: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Informe JSON sin procesar legible por máquina
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 1166,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Go": 1463925,
        "HCL": 10657,
        "Shell": 175057
      },
      "pushed_at": "2026-07-13T12:07:44Z",
      "created_at": "2026-04-22T04:40:24Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-13T12:08:05Z",
      "description": null,
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": null,
      "default_branch": "main",
      "license_spdx_raw": null,
      "primary_language": "Go",
      "significant_languages": [
        "Go",
        "Shell"
      ]
    },
    "owner": {
      "blog": "https://www.yolean.com",
      "name": "Yolean",
      "type": "Organization",
      "login": "Yolean",
      "company": null,
      "location": null,
      "followers": 9,
      "avatar_url": "https://avatars.githubusercontent.com/u/11188184?v=4",
      "created_at": "2015-02-25T05:49:14Z",
      "is_verified": null,
      "public_repos": 99,
      "account_age_days": 4165
    },
    "license": {
      "state": "absent",
      "spdx_id": null,
      "raw_spdx": null,
      "file_present": false,
      "scorecard_found": false,
      "profile_has_license": false
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2026-07-13T12:07:45Z"
        },
        {
          "tag": "v0.4.7",
          "kind": "patch",
          "published_at": "2026-06-22T15:52:32Z"
        },
        {
          "tag": "v0.4.6",
          "kind": "patch",
          "published_at": "2026-05-13T17:47:09Z"
        },
        {
          "tag": "v0.4.5",
          "kind": "patch",
          "published_at": "2026-05-12T10:50:04Z"
        },
        {
          "tag": "v0.4.4",
          "kind": "patch",
          "published_at": "2026-05-12T08:17:08Z"
        },
        {
          "tag": "v0.4.3",
          "kind": "patch",
          "published_at": "2026-05-11T19:31:46Z"
        },
        {
          "tag": "v0.4.2",
          "kind": "patch",
          "published_at": "2026-05-11T08:09:44Z"
        },
        {
          "tag": "v0.4.1",
          "kind": "patch",
          "published_at": "2026-05-07T10:13:10Z"
        },
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2026-05-04T15:16:19Z"
        },
        {
          "tag": "v0.3.8",
          "kind": "patch",
          "published_at": "2026-05-04T13:40:23Z"
        },
        {
          "tag": "v0.3.7",
          "kind": "patch",
          "published_at": "2026-05-03T15:38:42Z"
        },
        {
          "tag": "v0.3.6",
          "kind": "patch",
          "published_at": "2026-05-02T05:22:49Z"
        },
        {
          "tag": "v0.3.5",
          "kind": "patch",
          "published_at": "2026-05-01T19:04:46Z"
        },
        {
          "tag": "v0.3.4",
          "kind": "patch",
          "published_at": "2026-04-30T15:37:00Z"
        },
        {
          "tag": "v0.3.3",
          "kind": "patch",
          "published_at": "2026-04-30T09:52:37Z"
        },
        {
          "tag": "v0.3.2",
          "kind": "patch",
          "published_at": "2026-04-29T05:23:35Z"
        },
        {
          "tag": "v0.3.1",
          "kind": "patch",
          "published_at": "2026-04-28T08:46:37Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2026-04-27T12:15:05Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2026-04-25T15:47:38Z"
        },
        {
          "tag": "v0.1.0",
          "kind": "minor",
          "published_at": "2026-04-22T05:05:25Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "6e7b7132b6641f3a831f0fe134baa698a6017df5",
          "body": "Code review by Fable 5",
          "is_bot": false,
          "headline": "Merge pull request #30 from Yolean/integration-2026-07",
          "author_name": "solsson",
          "author_login": "solsson",
          "committed_at": "2026-07-13T12:07:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a097da147033adaba04fab1dc642a50d83e528c6",
          "body": "…ncy test\n\ndocker info runs under a 2s timeout that can occasionally time out\nunder CI load and succeed on the very next call, making two\nback-to-back DiscoverProvider() calls disagree even though the host\nhasn't changed. Cache the probe result for the process lifetime.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(provision/config): memoize DiscoverProvider to fix flaky idempote…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-13T11:53:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "981942575e39ae77d65c29e0c00c53fbeb8e99ac",
          "body": "…ifetime-unified reaper)\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'hetzner-provisioner-rebase' into integration-2026-07 (l…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:43:01Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5159f67484c3d59e45631ec7ae4f2fca3995eaa3",
          "body": "…diagnostics\n\nA pass-2 failure leaked the running VM (no t.Cleanup; the leaked\nVM then held the test's ports across reruns) and the sentinel\nFatalf discarded the command output that pinpoints whether the\nlabeled volume mounted at all.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(e2e/qemu): DataDisk test cleans up on failure and reports mount …",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:42:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2bc71a4d28ab3ba5e3c87ef183829761074d1d6c",
          "body": "…signalling\n\nTeardownConfig went straight to stopVM's SIGTERM ladder, which is\na hard power-off: guest writes from the last few seconds (inside\nthe ext4 commit interval) never reached disk. That silently lost\nrecent data on the operator-preserved DataDisk -- the disk-reuse\ncontract's own teardown co\n[…]\ns guestPoweroff (sync + poweroff over\nssh, wait for qemu exit) before the signal ladder; unreachable\nguests fall through within the ssh timeout.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(provision/qemu): teardown powers off the guest gracefully before …",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:42:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "74a8d3df6c54d8ad4f3eac25537f15720184e55c",
          "body": "e2e/hetzner_test.go is fenced behind the hetzner build tag and was\ninvisible to lint. Adding the tag surfaced no findings, so this is\ncoverage only.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(lint): cover hetzner-tagged e2e files",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:33:51Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8bb9f2f0ee53d353d5dc38644717da816793ebdc",
          "body": "…s a fresh window\n\nLifecycle parity with the local lifetime semantics: a manual stop\nends this run's budget and a start re-anchors the full window at\ncluster start. Stop deletes the reaper Job while the cluster is\nstill reachable (best-effort with a logged warning; a frozen Job\non a stopped server i\n[…]\nat provision, so no\nYAML config is needed. A failed re-arm fails Start loudly since\nan un-armed reaper on a running server is unbounded billing.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): stop deletes the expiry reaper; start re-arm…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:33:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1fce2a56698d8c0b672b9d46c1927d44492e490b",
          "body": "…drop autoTeardownHours\n\nThe v0.4.7 lifetime knob (maxRun Go-duration budget + onExpiry\naction; empty disables) replaces the hetzner-specific\nautoTeardownHours. The in-cluster reaper Job is hetzner's expiry\nmechanism, the analog of GCP's max-run-duration, so the earlier\nlifetime rejection inverts in\n[…]\nhe readiness gate and the new expires-at\nannotation stay covered.\n\nautoTeardownHours never shipped beyond this branch so no migration\nis needed.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/config): hetzner adopts the standard lifetime config; …",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:30:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6622f1cf3846b6ea21cae1ee2f4168b4c53f279f",
          "body": "…xpiry action\n\nThe reaper stops being teardown-only: installReaper takes a\nmaxRun window (seconds-resolution sleep) and an onExpiry action.\nteardown keeps the LB-first-then-server delete; stop is a graceful\nACPI shutdown that preserves the server identity. The Job carries\nmax-run / on-expiry / expir\n[…]\n\nProvision still drives this from autoTeardownHours with action\nteardown; the switch to the standard lifetime config follows in\nthe next commit.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(provision/hetzner): reaper Job parameterized on duration + e…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:24:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "14b4bbd77dd8c103191b67e0a8798c55e12ffd4b",
          "body": "…ration-2026-07\n\nDescriptions are now comma-free at the source so the generated schema\ncarries the full text instead of truncating at the first comma.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(schema): regenerate hetzner.schema.json after rebase onto integ…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:57Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "15ba93bf0d7b15eeab20261c0215e19b87bf6000",
          "body": "The canonical spec lives in the separate specs repo\n(specs/y-cluster/HETZNER_PROVISIONER.md); this repo does not carry\nspec documents. The specs repo copy needs updating from this\nbranch's version, which was ahead of it (reaper reconciliation,\nphases 6-7). Code comments now point at the specs repo instead of\nan in-repo path.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(specs): drop in-repo HETZNER_PROVISIONER.md copy",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ee344227567820614a834c2dff3e15d58742ef29",
          "body": "Picks up the lifetime + gateway resources definitions that main's\nCommonConfig gained since the branch forked, plus the corrected\nautoTeardownHours and rejectUpstream descriptions. Keeps the CI\ngenerate-drift job green.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(schema): regenerate hetzner.schema.json after rebase onto main",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "dfaea50e04f3678988d035049e464032a31cf0f2",
          "body": "backoffLimit: 0 + restartPolicy: Never meant the first pod failure\n(node reboot, eviction, transient error) permanently killed\nauto-teardown, contradicting the survives-cluster-reboots design.\nbackoffLimit: 6 re-schedules the pod; every retry sleeps the full\nHOURS again so the teardown only ever mov\n[…]\n (never fires\nearly), and the delete steps carry already-gone guards so a retry\nafter partial cleanup is harmless. Manifest test pins the value.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(provision/hetzner): reaper Job survives pod loss via backoffLimit",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "55758c90f4885eac122dda81c94f30ff2a877b6b",
          "body": "Three description/comment fixes and one validation rule:\n\n- rejectUpstream's jsonschema description contained a comma, which\n  is a field delimiter in jsonschema tags, so the generated schema\n  description was truncated to \"When true\". Reworded without the\n  comma.\n- autoTeardownHours' description s\n[…]\n hetzner and would silently\n  no-op otherwise. Unit test included; a disabled lifetime with only\n  the onExpiry tag default applied stays valid.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(provision/config): hetzner schema descriptions + lifetime rejection",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8250798dfccbe95e09f96087b4b1365847a5ac7e",
          "body": "- pkg/images/s3.go: explicitly ignore the deferred minio object\n  Close error, matching the repo idiom for read-side closes\n- pkg/provision/hetzner/hetzner.go: labelSelectorForGroup now uses\n  the labelManagedBy const instead of duplicating the literal\n  (the const was otherwise unused)\n- pkg/provis\n[…]\nFprintf instead of\n  WriteString(Sprintf(...)) (QF1012)\n- preload_test.go, reject_upstream_test.go: De Morgan on negated\n  conjunctions (QF1001)\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(lint): golangci-lint v2.11.4 findings in hetzner + images code",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fe507b55a448a29a07082e3a7cd3634108dc993b",
          "body": "…ing\" gap)\n\nBug: a pre-loaded image landed in containerd's k8s.io namespace\nunder the original push ref (e.g. \"hashicorp/http-echo:1.0.0\"),\nbut kubelet canonicalised that ref to \"docker.io/hashicorp/http-echo:1.0.0\"\nbefore the containerd lookup, found nothing, and pulled from\nupstream anyway. `kubec\n[…]\nHub registry).\n  - BuildPreloadScript_TagsCanonicalAliases asserts the script body\n    runs the right `ctr image tag` invocations.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(images): pre-load tags canonical Docker Hub aliases (closes \"Pull…",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6e490ebd2ac8c7cbb67a68878cf6931177fe7c98",
          "body": "Two new subcommands under the existing `images` group:\n\n  y-cluster images remote list   # ref / digest / blob-count per image\n  y-cluster images remote stats  # bucket-wide dedup + storage report\n\nThe list output is a TSV-shape table (works with `column -t` / awk):\n\n  REF                           \n[…]\nzes; the manifest line will always\ntotal ~KB (oci-layout + index.json), making any non-trivial\noci/ bytes recognisable as orphans.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(images): images remote list/stats operator-facing cache report",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2647e039aae105387e5fd86588e351d61f56e821",
          "body": "Closes the \"I have a provisioned Hetzner cluster but the LB IP is\nsilent\" gap. Two new pieces:\n\n1. Per-cluster default Gateway (pkg/provision/hetzner/default_gateway.go)\n\n   Provision now applies a Gateway resource in y-cluster-gateway\n   namespace after envoy-gateway's controller is up. Without thi\n[…]\nssions. Hostname has to match the HTTPRoute's hostname\nexactly because envoy-gateway routes by Host header, not by\ndestination IP.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): default Gateway + public-safe example workload",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9aa2d8172b01b29451f833d4cb9255766fed5f76",
          "body": "Two images sharing a layer now share storage and upload bandwidth.\n\nS3 layout v2: blobs hoisted from the per-image OCI prefix to a\nbucket-level content-addressed prefix.\n\n  Before (v1):\n    s3://<bucket>/oci/<safe-ref>/<digest>/blobs/sha256/<hex>\n    s3://<bucket>/oci/<safe-ref>/<digest>/index.json\n\n[…]\nd: bucket-with-many-entries makes\n    Provision slower (197s vs 112s on a 6-image bucket vs 1).\n    Operator decides what to push.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(images): layer dedup via content-addressed shared blobs (phase 7)",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "136e72da70ce41cf9e8bd2929a79e2209dd35e96",
          "body": "…chanism\n\nThe original design said \"drop registries.yaml with wildcard\nmirror to empty endpoint set\". E2E proved that's insufficient:\nk3s v1.35.4 falls back to the original registry despite the\nwildcard. Spec now documents what shipped:\n\n  - hosts.toml direct under certs.d/<reg>/ -- containerd treat\n[…]\nt's first pull of hetznercloud/cli.\n\nFuture agent sessions should land on the shipped mechanism, not\nthe original (broken) design.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(provision/hetzner): record rejectUpstream's hosts.toml-direct me…",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "285eb032d987dd4b899486756a8a6c3e7ca45012",
          "body": "….toml (phase 6.d)\n\nWhen HetznerConfig.ImageCache.RejectUpstream is true, the last\nstep of Provision drops:\n\n  1. /etc/rancher/k3s/registries.yaml -- k3s source-of-truth, so a\n     future `k3s server restart` regenerates certs.d the same way.\n  2. /var/lib/rancher/k3s/agent/etc/containerd/certs.d/<r\n[…]\now up.\n  - The reaper-readiness gate adds wall time to Provision but\n    is necessary -- a stuck reaper costs more than 7 seconds.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): rejectUpstream lockdown via containerd hosts…",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bd448cbfeb5b7c9739be74c2a648dbec5ddee058",
          "body": "When HetznerConfig.ImageCache.Bucket is set, Provision pulls every\nentry from s3://<bucket>/index.json into the node's containerd\nbetween MergeKubeconfig and the LB/cert/envoy-gateway steps.\nLands here so envoy-gateway's pull also benefits from cache hits.\n\nOperator side (pkg/images/preload.go):\n\n  \n[…]\n failed run grants read access to one cached image for the\n    same 24h. Acceptable for a dev cache shared inside one\n    project.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): pre-load images from S3 cache (phase 6.c)",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a388022708c139342fd429fade945e999f479425",
          "body": "`y-cluster images push <ref>` resolves a tag (or digest), runs the\nexisting pkg/images.Cache to materialise the OCI v1 image layout\nlocally, then mirrors the layout to s3://<bucket>/oci/<safe-ref>/<digest>/\nand merges an entry into s3://<bucket>/index.json.\n\nSmoke-tested against the live y-cluster-e\n[…]\nver AWS\ncredentials from a Hetzner-only project). Binary delta on a\nrelease build is +382KB; vs aws-sdk-go-v2 +147KB. Trade taken.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(images): push OCI layouts to Hetzner Object Storage (phase 6.b)",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c9d49933a272f980667476122d4737fbcc01e13c",
          "body": "…6.a)\n\nLays the config surface for the S3-backed image cache without\ntouching behavior. Bucket empty = cache disabled (the current\ndefault); a non-empty bucket flips the feature on and gets\nregional defaults (Region=hel1, IndexKey=index.json).\n\nValidation guards three failure modes the operator can \n[…]\nea. Description text still documents the\nruntime defaults for schema readers.\n\nJSON Schema regenerated via cmd/internal/schemagen.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/config): hetzner imageCache field + validation (phase …",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "04d9d2c09bf4cda9631a2be1cad5fcb026c31d58",
          "body": "Locks the design before the implementation lands so the operator\nsees the trade-offs in writing.\n\nThree opt-in deliverables under one HetznerConfig.imageCache field:\n\n  - operator-side `y-cluster images push <ref>` uploads an OCI\n    layout to s3://<bucket>/oci/<safe-ref>/<digest>/, mirroring\n    th\n[…]\nter CAS-via-etag pass).\n  - Layer dedup deferred to a follow-up phase if measurements\n    show large overlap across cached images.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(provision/hetzner): design image cache via Hetzner S3 (phase 6)",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c903ce232d99043072d467035d2d96af069e9263",
          "body": "…are-export, pause/resume)\n\nCloses the parity gap the spec end-goal #2 calls out.\n\n  - stop: hcloud Server.Shutdown via hetzner.Stop. Graceful ACPI;\n    operator gets the cluster back via `start` without a re-provision.\n    Billing continues for the disk while stopped (Hetzner has no\n    \"frozen, no\n[…]\nectation that it's coming.\n\nAdds hetzner.HasState (sidecar-presence probe) for the\nprepare-export and start branches; unit-tested.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): lifecycle dispatch parity (stop, start, prep…",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8652ef7ce0c8449a12f437091414d965b3f6ef5e",
          "body": "…shipped reaper\n\nThe spec referenced from TMP_HANDOVER.txt as the \"first read\" did not exist on\ndisk; check it in so future agent sessions actually land on a Phases table that\nmatches the code.\n\nSpec deltas vs. the original draft (recorded so future readers don't get\nmisled by the locked Decisions t\n[…]\nJob\".\n  - pkg/provision/hetzner/hetzner.go package-doc phase list: phase 2 is\n    in-cluster reaper, phase 4 is positional source.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(provision/hetzner): land HETZNER_PROVISIONER.md, reconcile with …",
          "author_name": "Yolean macbot01",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "07f2c4f6dbfbd691233f9765b459445761e7e513",
          "body": "Replaces the \"auto-teardown not implemented; run teardown\nyourself\" Warn with a real cluster-side reaper that survives the\noperator's machine going away. The trigger lives ON the cluster\n(an embedded Kubernetes Job), so a wiped/retired/quit-employee\nlaptop no longer strands the paid Hetzner resource\n[…]\nter reaper completes,\nthe operator's interactive y-cluster teardown sweeps the\norphaned cert + SSH key, leaving the project empty.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): in-cluster auto-teardown reaper Job (phase 2)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bad20ef1046b8c869a947032bc8be8c58db439c7",
          "body": "…hase 3.c.2)\n\nWires the cert generator from 087f35d into the LB lifecycle so\nclients dialing the LB on 443 get a real TLS handshake against\na per-context self-signed cert, with SNI selecting the right cert\nwhen multiple contexts share an lb-group LB.\n\nLB service shape changed:\n\n  - 80: TCP -> 80 (kl\n[…]\n). That can't happen under the\nnormal Provision-always-adds-a-cert flow but tolerates an\noperator who manually mucked with the LB.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): LB-side TLS termination via uploaded cert (p…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d8a75e4baf1247e4d954dca800ea9b3ecece2cb7",
          "body": "Pure crypto/x509 helper that produces a PEM-encoded self-signed\ncert + RSA private key for the per-context TLS termination wired\nin the next commit. No Hetzner API calls, no LB integration --\njust the byte-shape Hetzner Certificate.Create needs.\n\nDecisions worth keeping:\n\n  - Self-signed leaf, no se\n[…]\nIP regression\nguards against the gotcha of net.ParseIP returning a nil net.IP\nthat crypto/x509 would still accept and crash later.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): self-signed cert generator (phase 3.c.1)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b376c8f2d2a2919635541e3288d324fd9bfef978",
          "body": "Hetzner's create-load-balancer-with-services API rejects a TCP\nhealth_check that omits the port field (responds with a generic\n\"invalid input in field 'services'\"); the CLI adds the\ndestination_port as default, but the API itself does not.\n\nTwo issues fixed:\n\n  1. health_check.Port now set explicitl\n[…]\no containerd, teardown -> empty project. Both LB services\nreport health_check.port == listen_port == destination_port\nas expected.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(provision/hetzner): explicit per-service LB health-check port",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e194d29e506cbddb31313e2c65652bc1b9c0cf63",
          "body": "Phase 2 attempted host-side at(1) scheduling for auto-teardown.\nRejected by Staffan on the architectural ground that a laptop\nwhich gets wiped, retired, or simply belongs to someone who quit\nleaves the Hetzner server stranded forever -- the exact \"don't\nleak\" failure mode auto-teardown is supposed t\n[…]\nzner/auto_teardown_test.go\n  - state.AtJobID field\n  - the scheduleAutoTeardown / atRemove call sites in\n    Provision / Teardown.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "revert(provision/hetzner): drop at(1) auto-teardown; pin to follow-up",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ac040112fdad29e0cb33d7a4e871adf8e58dbcaf",
          "body": "Wires the hetzner provisioner into the cluster.Lookup detection\nchain so \\`y-cluster ctr\\`, \\`y-cluster crictl\\`, \\`y-cluster\nmanifests add\\`, and \\`y-cluster images load\\` all work against a\nHetzner-provisioned cluster the same way they work against qemu /\ndocker / multipass.\n\nDetection: <cache-dir\n[…]\nerRunning_MissingOrInvalid pins the\n    fall-through-on-bad-state behaviour so Lookup doesn't\n    produce a half-populated result.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cluster): hetzner backend in Lookup; testdata example (phase 5)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1f28f68b274ae703f829eddd771852e8e676d70c",
          "body": "\\`y-cluster images load <url>\\` now accepts an http(s):// URL as\ninput source, in addition to a file path or \"-\". The byte stream\nis the contract; the helper just opens an HTTP GET and pipes the\nresponse body into the same downstream code path that file and\nstdin use. The motivating use case is the \n[…]\ntx deadline so\n    a TEST-NET-1 connect attempt fails fast.\n  - TestOpenInput_FileBranch / _StdinBranch as regression\n    pinning.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(cmd/y-cluster): http(s) URL input for images load (phase 4)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4fb52e068ac3ebe809c1e7e745eedd8164c58bac",
          "body": "…e 3.b)\n\nAfter ensureLoadBalancer, Provision now installs envoy-gateway via\nthe existing pkg/provision/envoygateway helper and stamps the LB's\npublic IPv4 onto the y-cluster GatewayClass under\nyolean.se/dns-hint-ip. ystack's y-k8s-ingress-hosts walks the\nGatewayClass annotation to populate /etc/host\n[…]\nothing on the node.\n\nPhase 3.c will land cert-manager + Listener TLS so the LB's 443\nservice has a real HTTPS responder behind it.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): envoy-gateway + dns-hint-ip on LB IPv4 (phas…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b601ab4ca4672edacfe744b801cb113e76a9cd98",
          "body": "Provision now ensures a Hetzner LoadBalancer for cfg.LBGroup\n(default = \\$USER) and includes the new server. Teardown deletes\nthe LB iff this server was the last lb-group member, so multi-\nmachine devs share one LB and pay for it only while at least one\ncluster is up.\n\nArchitecture:\n\n  - LB name: y-\n[…]\nrMatchesServerCreate pin\nthe name shape and the invariant that the LB's label_selector\nresolves the same servers Provision tagged.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): shared lb-group LB attach (phase 3.a)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1b990455d98206b6080f4c3a8ea33ea2abb15ae8",
          "body": "Schedules a host-side at(1) job at the end of Provision that runs\n\\`y-cluster teardown -c <Dir>\\` after cfg.AutoTeardownHours hours\n(default 8). The job id is captured in the state sidecar so\nTeardown can atrm it cleanly; if the operator misses the window,\natd runs the missed job at next boot, which\n[…]\nuns only when HCLOUD_TOKEN is\nexported) -- a cheaper unit test would mock exec.Command, which\nis overkill for a four-call wrapper.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): at(1) auto-teardown (phase 2)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "361adfc5d289f8a9799d15b2ef7f376c4eb753c8",
          "body": "Wires the install half of phase 1 onto the bare Provision/Teardown\nlanded in 2a8df37:\n\n  - installK3s runs the canonical curl|sh installer over SSH after\n    waitForSSH succeeds. Flags: --tls-san=<ipv4> +\n    --node-external-ip=<ipv4> so the kubeconfig the operator pulls\n    back is dialable, plus t\n[…]\ne envoy-gateway\n    rollout to the shared LB in phase 3; doing it here would mean\n    a half-functional gateway pointing at no LB.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): k3s install + kubeconfig merge (phase 1.b)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b5d13338f81f2617525325ae6366a5f31ef06a4b",
          "body": "The hetzner provisioner now creates and tears down Hetzner Cloud\nservers. NO k3s install or LoadBalancer yet -- this commit lands\nthe lifecycle bones plus the SSH wiring so phase 1.b can do the\nin-server install over the same SSH channel cluster.Lookup will\nlater use for ctr / crictl / RunShell.\n\nWh\n[…]\nuse Hetzner's image ships with a\n    `preserve_hostname: true` default that ignores cloud-init's\n    hostname directive otherwise.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/hetzner): bare Provision/Teardown (phase 1)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "412f9997917807dde0e72300adea7fd2f3e25bbc",
          "body": "First step of the Hetzner provisioner branch: types, validation\nrules, and dispatch. No Hetzner Cloud API calls land yet -- this\njust lets the build know that \"hetzner\" is a real provider value\nand rejects malformed configs at load time.\n\nWhat lands\n\n  - ProviderHetzner const and AllProviders entry.\n[…]\nfety\n    belt). Settled on \"0/unset = use default, mandatory\". A truly\n    long-running dev cluster needs an explicit hours value.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(provision/config): hetzner provider scaffolding (phase 0)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T11:13:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "03fff8e55c13dc34d4e8233931965ce18b37dbd2",
          "body": "…rmin kernel-selection guard)\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'prepare-export-contract' into integration-2026-07 (supe…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T08:38:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "be19ec37cdfa6516c9915c3c5e76b24138094dcf",
          "body": "…election\n\nsupermin builds its appliance from the NEWEST /boot/vmlinuz-* that\nhas a matching /lib/modules/<release> dir, not from the running\nkernel. The guard checked only the running kernel, so a host with\na newer 0600 kernel installed but not yet booted (the normal state\nafter an unattended kerne\n[…]\non (numeric release ordering, module-dir\ngate, running-kernel fallback) in both the binary and the sourced\nscripts/_check-host-kernel.sh helper.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(libguestfs): kernel-readability guard mirrors supermin's kernel s…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T08:38:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "95e6c10224c9fc664abe0e9f03e80d0eca521b35",
          "body": "…ed-disk instance-id, lint coverage, schema descriptions)\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'prepare-export-contract' into integration-2026-07 (stag…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T08:25:31Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b46d25b955ec198524e68a2536f1397328262d2e",
          "body": "Commas are field delimiters in jsonschema struct tags, so every\ndescription containing one shipped truncated in the generated\nschemas: gateway.skip rendered as just \"If true\", the resource\nrequest docs cut at \"Default cpu 10m\", the notation examples cut\nat \"(e.g. 10m\", and the multipass image / localstorage\npathPattern docs lost their tails. Reworded without commas and\nregenerated.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(provision/config): comma-free jsonschema descriptions",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T08:23:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8ae2d6d3a56d31e5e0de2e450cf1a0918b8abcca",
          "body": "golangci-lint ran without build tags locally and in CI, so every\nfile behind the e2e/docker/kvm/multipass tags was never linted.\nAdd the tags to .golangci.yaml and fix what surfaced: two\nerrcheck misses (net.Listener Close in the registry helper,\nbest-effort kubectl delete in the yconverge e2e) and one QF1001.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(lint): cover tag-fenced e2e files, clear the debt that hid there",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T08:22:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d2e7667709f2c1cfbfa4ad48c8194dc85d53a803",
          "body": "…vision can SSH\n\nProvision always generates a fresh SSH keypair (ensureSSHKey\ndeletes and regenerates) and relies on cloud-init to install the\npublic half. cloud-localds' default meta-data hardcodes\ninstance-id iid-local01, and cloud-init only re-applies user-data\nwhen the instance-id changes, so bo\n[…]\nage, so\nthe id changes only across provisions, where the keypair changes\nanyway. The meta-data file joins the per-VM artefact list for\nteardown.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(provision/qemu): unique cloud-init instance-id so staged-disk pro…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T08:22:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ab1ec7502f0b7c858777b5c038725c75980eb00a",
          "body": "…contract alignment)\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'prepare-export-contract' into integration-2026-07 (e2e …",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T07:58:57Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3f0e465ea03de1eced7b9986a5b7a185bbdcb950",
          "body": "…ract\n\nThree kvm-gated tests still ran the retired stop-then-prepare\nsequence, which PrepareExport has rejected since it gained the\nlive phase (it needs the apiserver up and stops the VM itself).\nCI never runs the kvm leg, so v0.4.7 shipped with\nTestQemu_PrepareExport_GracefulShutdown, TestQemu_Seed\n[…]\nnged: the\nSIGTERM window under test is prepare-export's internal stop,\nwhich is the same lifecycle.Stop path the tests called\nexplicitly before.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(e2e/qemu): align prepare-export callers with the live-phase cont…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T07:58:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cfe2f18a6d402441860296fc90600b445b1cf288",
          "body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'k3s-1.35.6' into integration-2026-07",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T07:11:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ac75eba0f284870dd13af78b1e31483364d4b941",
          "body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'envoy-gateway-1.7.5' into integration-2026-07",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T07:08:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3014fca21365ab316756174536f10f0787ac0ae3",
          "body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'prepare-export-contract' into integration-2026-07",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T07:08:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7ffdfd9da9d01f87e42f9595e3517704d9f46235",
          "body": "Two patch releases on the supported v1.35 channel, carrying the\nupstream Kubernetes security fixes. Schemas regenerated per the\npin file's bumping flow.\n\nThe ghcr mirror tag does not exist until mirror-k3s.yaml runs on\nthe path change after this merges to Yolean main (or is\nworkflow-dispatched there); until then provisions resolve the\nimage via the documented docker.ResolveImage fallback to\ndocker.io/rancher/k3s with a warning.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "build(k3s): bump pin v1.35.4+k3s1 -> v1.35.6+k3s1",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T07:03:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fae52abb6e68e9f72ed48b7c6ea43e9eba241a1e",
          "body": "v1.7.5 (2026-07-08) bumps the bundled Envoy proxy to 1.37.5 which\nincludes multiple upstream security fixes, and the v1.7.3/v1.7.4\npatches in between carried an auth fail-open fix. Same minor\nline, so the CRD/controller surface is unchanged.\n\nThe package doc had drifted badly enough to mislead exact\n[…]\ndownloads install.yaml per version into the\ncache on first use and renders the GatewayClass in Go. Rewritten\nto describe the mechanism as built.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "build(envoygateway): bump Envoy Gateway pin v1.7.2 -> v1.7.5",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T07:00:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ca6783d3c91f4adf0effa498e6433057e05911d0",
          "body": "Implements option 1 of the specs repo's\nISSUE_QEMU_PROVISION_SSH_TIMEOUT.md: cold-cache first boots spend\n5-15 minutes in cloud-init and the 120s abort left qemu running,\nso the next provision hit \"VM already running (pid N). Teardown\nfirst\". Heartbeat lines every 30s and a console-log pointer in\nboth the initial log line and the timeout error replace the\nsilent wait.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(provision/qemu): 600s SSH wait with heartbeat, was 120s",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T06:57:13Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8583a30b646f5713260c2a3be4a90dd1e135262e",
          "body": "…e no Gateway API\n\nThe live phase hardcoded GatewayClass \"y-cluster\" even though\ngateway.className is configurable, and the configured name is not\nrecoverable from the qemu state sidecar. A deploy on a renamed\nclass failed prepare-export outright (ClearDNSHintIPAnnotation\nerrors on a missing class d\n[…]\nn stays for the\n  explicit --gateway-class CLI path, with its comment corrected:\n  a missing class fails loudly there, which suits a typed name.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(prepare-export): clear dns-hint-ip on all GatewayClasses, tolerat…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T06:56:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5c51301c7cb725e0e5c3c1b1850fd027f673e9bd",
          "body": "The stop-first sequence in the prepare-export help text, its file\ncomment and APPLIANCE_MAINTENANCE.md predated the live phase: the\nimplementation errors unless the VM is running (it needs the\napiserver to clear dns-hint-ip and snapshot gateway state) and\nstops the VM itself before the offline phase\n[…]\no\nvirt-customize, the stale qemu-only claim on the lifecycle comment\n(stop dispatches to all three backends) and the gateway command\nchild list.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: prepare-export contract is provision then prepare-export",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T06:54:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b1c188c1b923c893e796d7835af647dc322ee5cf",
          "body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'security-toolchain-bumps' into integration-2026-07",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T06:47:10Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a4473fc149423eb3f40f4486883f1c985aa5c00c",
          "body": "Integration work branch: collects CI-green unmerged increments for\nreview. Upstream PRs will be replayed from the individual branches.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'appliance-workflows-rebase' into integration-2026-07",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T06:47:10Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a387d1f0f7a406440e69dca60d0b41464e5e5b4b",
          "body": "govulncheck reports 18 vulnerabilities in called code at the previous\npins, all cleared by these three bumps:\n\n- Go 1.26.1 -> 1.26.5: 11 reachable stdlib fixes, including the\n  crypto/x509 name-constraints bypass (GO-2026-4866) and net/http\n  fixes. CI reads go-version-file so lint/test/build/releas\n[…]\nix GO-2026-5026.\n\nx/sync, x/sys, x/text move as transitive requirements of the above.\nUnit tests and golangci-lint v2.11.4 pass at the new pins.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "build(deps): Go 1.26.5, x/crypto v0.54.0, x/net v0.57.0",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T06:14:30Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "978086d643fd0d5ba2aacd3044f025e40fc73781",
          "body": "The probe window message did arithmetic on ATTEMPTS which was never\nassigned (the probe() local is lowercase attempts), so the failure\npath reported \"never answered within 0s\". Name the shared default\nPROBE_ATTEMPTS and use it in both places.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(scripts/e2e-hetzner): failure diagnostics referenced unset ATTEMPTS",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-07-10T06:07:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "809b948482da5c4c7be6335833271ebc94655fff",
          "body": "…ernel helper\n\nNow that v0.4.7 (PR #29) shipped the lifetime feature, the libguestfs\nhost-kernel check, and scripts/_check-host-kernel.sh to main, wire the\nappliance scripts -- rebased on top of that release -- to actually use\nthem:\n\n- All four appliance build / e2e scripts now source\n  scripts/_che\n[…]\nd). The\n  GCP e2e sets a lifetime and asserts the instance's scheduling shows\n  maxRunDuration + instanceTerminationAction=DELETE.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(scripts): integrate appliance scripts with released lifetime + k…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:04:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "95c89e8a17c723c4e949156da427496198f924e5",
          "body": "Both files-pointed-at-by-env-var inputs surfaced the same\nfoot-gun: a malformed value passed the existence check but\nfailed deep inside the tool we shelled into, with a less\nhelpful message:\n\n  - GCP_KEY pointing at a truncated / wrong-format JSON\n    (e.g. a re-exported key that lost its private_ke\n[…]\n  it at config-load time with a message naming the valid\n    values.\n\nBoth checks fire BEFORE any cloud-side state change. Adds no\nnew dependency: jq is already required by the broader\nappliance flow.",
          "is_bot": false,
          "headline": "feat(scripts): fail-fast schema checks on GCP_KEY and H_S3_REGION",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c2eabc70a5ceaf2b4d5829f31d05cd462acff179",
          "body": "The previous commit added \"e2-medium's\" and \"there's\" inside the\nsingle-quoted YHELP heredoc. Single quotes in bash can't contain\nsingle quotes, so the apostrophes terminated the string mid-block;\nthe resumed unquoted \"4 GiB OOMs ...\" got parsed as a command,\nand any consumer that sourced or executed the help block saw\n\"line 76: 4: command not found\".\n\nReworded to avoid the apostrophes entirely. bash -n parses the\nfile clean and --help renders the section as intended.",
          "is_bot": false,
          "headline": "fix(scripts/qemu-to-gcp): drop apostrophes from YHELP block",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f3535e6dd6eadc636f649785948ddb7d6c4c32b1",
          "body": "…each build)",
          "is_bot": false,
          "headline": "GCP NEG endpoint re-attach is idempotent on re-runs (VM is recreated …",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1875afc46d8e9323b8377e97d906b7cc61d560c6",
          "body": "…e stack)\n\nObserved an appliance build that ran fine for ~2h at 91-93% memory\non a 4 GiB e2-medium, then died at 100% CPU / 3807 MiB used: ssh\nbanner exchange timed out, :443 + :6443 went REFUSED while :80\nkept LISTEN with the userspace too starved to respond. Classic OOM\nspiral. The full appliance \n[…]\nlp\ntext and the default-assignment comment so the next operator\nreading either spot sees why we don't surface a GCP_MEMORY knob.\nGCP_MACHINE_TYPE stays as the escape hatch for highmem / larger\nshapes.",
          "is_bot": false,
          "headline": "fix(scripts/qemu-to-gcp): default to e2-standard-2 (e2-medium OOMs th…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "70d65711a025103898c57f912000469182b0b3b3",
          "body": "…hooks\n\nThe unattended flow had ASSUME_YES + TLS_DOMAINS=auto landed\nalready, but no work-doing hook in PROMPT 1's hands-on window.\nResult: a build with ASSUME_YES=1 reached prepare-export with\nonly the y-cluster echo HTTPRoute applied; TLS_DOMAINS=auto\nthen aborted because the cluster had no non-wi\n[…]\nTE_VM_IP, etc.) are exported as empty strings.\n\nNon-zero exit aborts under set -e. Local cluster / VM / LB\nstay up for inspection.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(scripts/qemu-to-gcp): APPLIANCE_SEED_CMD + APPLIANCE_VERIFY_CMD …",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "950cab27f8115d4b3c65c93f0ceb637ade5a3668",
          "body": "Drops the parallel-list footgun: today the operator declares\nhostnames in HTTPRoute manifests AND in TLS_DOMAINS, and drift\nbetween the two means the LB cert covers hostnames the cluster\ndoesn't serve, or vice versa.\n\nSetting TLS_DOMAINS=auto now resolves the FQDN list by calling\n`y-cluster gateway \n[…]\nefore.\n\nEmpty result aborts with an explicit error (operator asked for\nauto, none found = something wrong with the cluster state).\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(scripts/qemu-to-gcp): TLS_DOMAINS=auto derives from gateway state",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8e60515a51bf99ef6cc89379ebf4ba127d5744cd",
          "body": "PR #20 changed prepare-export to require the cluster RUNNING:\nits live phase clears the per-deploy dns-hint-ip annotation\nand snapshots reconciled Gateway state into <cacheDir>/<name>-\ngateway-state.json (both need the apiserver up). prepare-export\nthen stops the VM itself before its offline (virt-c\n[…]\nst the stopped VM.\n\nDrop the explicit stop call. Update the docstring stage list\nto reflect that prepare-export does its own stop.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(scripts/qemu-to-gcp): drop explicit stop before prepare-export",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3b37bf345fc09efc415e9d6da8038cfa5a051540",
          "body": "The build VM occasionally OOMs during heavier customer\nworkloads applied at PROMPT 1 (mariadb + kafka + envoy +\nthe bundled controllers all in 4GB is tight). 8GB matches\nthe y-cluster default for stand-alone provisions but the\nqemu-to-gcp script was overriding it down to 4GB to keep\nthe host's headr\n[…]\ng.QEMUConfig.applyDefaults), so other provisioner\nflows (multipass, docker, plain qemu) are not affected.\nDisk size stays at 40GB.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(scripts/qemu-to-gcp): bump build VM memory 4096 -> 8192",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c45b8e98bfe04fd79f5f341394bf412452e09d64",
          "body": "…own-side PRESERVED message\n\nState preservation across appliance redeploys is the overarching\ndesign goal of the data-seed mechanism (commit f69addf +\nAPPLIANCE_MAINTENANCE.md). What was missing on the operator-\nfacing side: the QA-flow build script silently reused the\npersistent disk on every redep\n[…]\nhe revert of the route-\nenumeration block that this same teardown-issue debugging\nsurfaced as post-import SSH+kubectl scope-creep.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(scripts/qemu-to-gcp): explicit --reuse-disk / --keep-disk; teard…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ab1f5c71dc22165a6fe31852d70c32111240cebe",
          "body": "Two related fixes for the GCP appliance smoke flow:\n\n1. do_tls_frontend now creates a :80 forwarding rule that 301s\n   to :443. Previously the function set up only a :443 listener,\n   so any `curl http://<lb-ip>/...` against the LB IP hung at TCP\n   connect (no listener on 80). Hangs from `curl ... \n[…]\ninst ext-app01-* in this commit (would require\nmutating an in-use LB the operator owns); it lands on the next\ndo_tls_frontend run.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(scripts/qemu-to-gcp): :80 -> :443 LB redirect + Gateway-route probe",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7ce65b73d9e4ec91457c1625e893831359bae5c9",
          "body": "Adds a post-deploy step that offers to stand up a GCP regional\nExternal Application Load Balancer in front of the appliance VM\nwith a self-signed cert covering operator-supplied FQDNs.\nIdempotent (describe-then-create) so re-runs converge; teardown\nintegrated into the existing teardown subcommand.\n\n\n[…]\nsing resources are not\nerrors. The `Will DELETE:` inventory now lists `${NAME}-tls-*`\nwhen a forwarding rule of that shape exists.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(scripts/qemu-to-gcp): optional regional HTTPS LB at end-of-build",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ed68ea61e65bbb678f63260ac711281510a1aaa0",
          "body": "Symmetric with APP_HTTP_PORT / APP_API_PORT: a new\nAPP_HTTPS_PORT env var lets operators override the host port\nforwarded to guest 443. Unset means \"let y-cluster apply its\ndefault\" -- the YAML still omits the field when no port var is\nset, which matches the behaviour for the other ports.\n\nWithout t\n[…]\nmodern Linux distros allows binding 443 without root the same\nway 80 already does.\n\nYHELP entries updated to surface the new knob.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(scripts): also forward host:guest 443 conditionally",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4df691388a06831ce1ad7117a095d21aedf454b3",
          "body": "The appliance-build / e2e scripts each carried a defaults block:\n\n    APP_HTTP_PORT=\"${APP_HTTP_PORT:-80}\"\n    APP_API_PORT=\"${APP_API_PORT:-39443}\"\n    APP_SSH_PORT=\"${APP_SSH_PORT:-2229}\"\n\nthen interpolated those into the heredoc'd y-cluster-provision.yaml.\nThree of the four values restate y-clust\n[…]\nft as-is (test-only; the import-side qemu is started directly,\nno y-cluster CLI involvement, so y-cluster's defaults don't\napply).\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(scripts): drop port defaults from bash, defer to y-cluster's",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5a3c67d4db709ef9d74481420aa87e3a70adc585",
          "body": "Appliance e2e / build flows install workloads, build a seed\ntarball, prepare-export, and re-boot from the prepared disk -- the\ncumulative footprint pushes the 20G default disk into pressure on\nthe kubelet's image-gc thresholds, which surfaces as flaky pod\nevictions mid-test or mid-build.\n\nBump to 40\n[…]\ns with actual\nusage; the larger virtual size is a no-cost ceiling. The GCE side\nsimilarly uses a thin-provisioned persistent disk.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: bump appliance VM/disk size to 40G (avoid disk-pressure flakes)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "006ae88ebf0861cfecc69866a7d61dac918c57e1",
          "body": "Yolean dev / setup scripts that smoke-test the gateway expect a\nhost-side port that reaches guest 80. Today's qemu-side host port\nforwards default to 39080 in both the Go e2e helper and the bash\nappliance-build scripts, so any consumer that hardcodes\nhttp://localhost:80 has to remember the offset.\n\n\n[…]\nurl examples updated to match. Override via env\n    (APP_HTTP_PORT=39080 ./scripts/...) on hosts that keep port 80\n    privileged.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: align local gateway access on port 80 (e2e + scripts)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8f9c276b61619321f786203281f9bc71cb899501",
          "body": "Brings every scripts/ change from agents/appliance-export-import\nto upstream main as a single bump. The Go and testdata side of\nthis work landed in #19 (appliance-primitives); this commit is\nthe operator-facing bash that drives the released binary\nthrough the appliance lifecycle, plus the .env-style\n[…]\n #19. Both `go build ./...` and `go test\n./...` are unchanged-clean on this branch -- the scripts add\nno go.mod or testdata edits.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(scripts): appliance build / publish / e2e drivers",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T16:01:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6af8cc4357ab0e3f77c5fe2d90554b039f3732d9",
          "body": "Teardown automation",
          "is_bot": false,
          "headline": "Merge pull request #29 from Yolean/teardown-automation",
          "author_name": "solsson",
          "author_login": "solsson",
          "committed_at": "2026-06-22T15:51:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d8f764bb43d5e5610b06e2cf215a388259622596",
          "body": "Surfaced when PR #29 rebased this work onto main and CI ran on it for\nthe first time.\n\nLint (staticcheck):\n- ST1005 (pkg/provision/qemu/libguestfs.go): the remediation error\n  string ended with a period. Drop it; the multi-line body is unchanged\n  (only a trailing newline/punctuation trips ST1005).\n\n[…]\nsources it yet: the appliance workflow branch (which carries the\nappliance-*.sh scripts that source it) will be rebased onto this.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ci): lint + the GHA failure with the libguestfs setup helper",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T15:46:54Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bfb0fb60f0eb03e51672755b12987f47fb3139cb",
          "body": "libguestfs (virt-customize / virt-sysprep / virt-tar-out / virt-format)\nbuilds a supermin appliance from /boot/vmlinuz-$(uname -r). Ubuntu ships\nthose images mode 0600, so after every kernel upgrade a fresh root-only\nimage lands and the tools fail with the opaque \"supermin exited with\nerror status 1\n[…]\nifies the host. The remedy is\na single copy-pasteable block the user runs once with sudo; the hook\nthen covers all future kernels.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(libguestfs): one durable remedy for unreadable host kernel",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T08:57:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b7b3cde8f0bf4981ae35685c22b970110e95b7f3",
          "body": "A dev cluster left running after a task is paused or finished is pure\ncost. A lifetime.maxRun budget makes the cluster expire on its own,\ntaking the cheapest environment-appropriate action.\n\nModel:\n- Trigger is an absolute TTL (maxRun, a Go duration), counted from\n  when the cluster STARTS, re-ancho\n[…]\nlifecycle surface; docker/multipass keep the \"not yet implemented\"\nshape. Idle-based expiry and an in-cluster reaper are deferred.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(lifetime): cost-control auto-expiry for clusters",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-06-22T08:55:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c370b31cba8bdfe0b35176e623729bb670165a77",
          "body": "Primitives for qemu data disk reuse",
          "is_bot": false,
          "headline": "Merge pull request #28 from Yolean/qemu-data-disk-reuse",
          "author_name": "solsson",
          "author_login": "solsson",
          "committed_at": "2026-05-13T17:46:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "de6c8de75e14c404efa718805992fdb28aa40acb",
          "body": "Pre-FR 4 the import -> boot path was a deadlock:\n\n  - `y-cluster import <disk>` writes <CacheDir>/<Name>.qcow2\n  - `y-cluster provision` errors: \"disk already exists; run\n    teardown or start\"\n  - `y-cluster start` errors: \"kubeconfig context X has no\n    associated cluster; nothing to start\" -- th\n[…]\n to.\n\n  TestQemu_ExportImport (the VMDK-flavoured counterpart) takes\n  the same code path; same FR 4 fix unblocks it.\n\nRefs:\n  - specs/y-cluster/FEATURE_REQUEST_DISK_REUSE_E2E_PRIMITIVES.md\n    (FR 4)",
          "is_bot": false,
          "headline": "feat(provision/qemu): provision uses staged disk from import (FR 4)",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-13T16:00:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e1c278bd7e208a417e6aa193ef20506b9d47a874",
          "body": "Two of the three FRs from\nspecs/y-cluster/FEATURE_REQUEST_DISK_REUSE_E2E_PRIMITIVES.md\nthe checkit maintainer filed against the local-qemu disk-reuse\nflow. FR 2 (`--first-boot-only`) is deferred -- the spec marks\nit as needing a design pass on marker storage / mount semantics /\nverb shape, and that \n[…]\ng lives on `add` (with a\nflag-mismatch error from `replace`) or a separate verb\n`add-first-boot`. Worth a design pass before code.\n\nRefs:\n- specs/y-cluster/FEATURE_REQUEST_DISK_REUSE_E2E_PRIMITIVES.md",
          "is_bot": false,
          "headline": "feat(manifests, import): scope adds for the appliance disk-reuse PoC",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-13T12:10:00Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4b885726e3cf30cfcfc080c65e1b66b9d4cdceff",
          "body": "Adds an operator-facing primitive that exposes the labeled\ndata-volume mechanic the appliance flow uses in cloud, but\nthrough the local qemu provisioner. The maintainer no longer\nhas to round-trip through prepare-export + GCP / Hetzner\nimport to verify a disk-reuse scenario.\n\nSurface:\n\n  - QEMUConfi\n[…]\n  re-provision same DataDisk -> read sentinel back.\n    Closes the coverage gap where the only existing\n    appliance-volume e2e went through prepare-export +\n    seed-tarball (a different code path).",
          "is_bot": false,
          "headline": "feat(provision/qemu): DataDisk for local disk-reuse QA",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-13T08:05:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3b0ca7365a1219c2f4a1e4b82cb87c540c26559a",
          "body": "Fix digest-only image tagging and gateway resource requests, again",
          "is_bot": false,
          "headline": "Merge pull request #26 from Yolean/fix-aliasfor-and-controller-patch",
          "author_name": "solsson",
          "author_login": "solsson",
          "committed_at": "2026-05-12T10:41:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f1ae8c1f0723f01a41acfa4e36bbcac1e11a7dde",
          "body": "…ranches\n\nTestEnvoyGateway_InstallAgainstKwok was calling Install with the\nfour resource-request fields left zero, which short-circuited\nboth the kubectl-patch branch (controller) and the EnvoyProxy CR\nbranch (proxy). That's how PR #25's \"kubectl rejects the partial\nDeployment manifest\" regression s\n[…]\nfuture regression where the\npatch step generates an invalid Deployment or the EnvoyProxy CR\nisn't applied will surface here without needing a full\ndocker/qemu e2e.\n\nRefs the kubectl-patch fix b8ec43d.",
          "is_bot": false,
          "headline": "test(e2e/envoygateway): exercise patch + EnvoyProxy + parametersRef b…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-12T10:26:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7a6e69d132dd66be1d54bdaaf2cc30eddf5ce3f1",
          "body": "…gest\n\naliasFor was added in PR #23 to skip the bare sha256:<hex>\nconfig-digest row and to synthesize a :latest@digest alias for\ndigest-only refs. It missed the fourth shape, tag+digest\n(\"<repo>:<tag>@<digest>\"), which is what y-site-images-load\nemits today: every line in the input was logging\n\n  WA\n[…]\n \":\" after the last \"/\"\nto avoid host:port false positives.\n\nTestAliasFor grows the four-shape table: adds tag+digest,\n:latest+digest, and a hostport tag+digest case.\n\nRefs PR #23, /tmp/appliance.log.",
          "is_bot": false,
          "headline": "fix(images): aliasFor on tag+digest input drops the tag, keeps the di…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-12T10:18:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b8ec43da41388d0bce2d9473a30d5c691a6213ad",
          "body": "…ontroller resources\n\nkubectl apply --server-side validates the manifest against the\napps/v1 Deployment schema client-side; a partial manifest\ndeclaring only resources.requests fails with \"spec.selector:\nRequired value\" / \"containers[0].image: Required value\" before\nthe request reaches the API serve\n[…]\npinned via TestControllerResourcesPatch_RequestsOnly:\npatch body asserts neither apiVersion nor kind nor metadata,\nand rejects accidental limits / image declarations.\n\nRefs PR #25, /tmp/appliance.log.",
          "is_bot": false,
          "headline": "fix(provision/envoygateway): kubectl patch instead of SSA-apply for c…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-12T10:18:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4d70fa8b2affd843a8bb1f9116da5a29132cb817",
          "body": "…-requests\n\nGateway API reduce default resource requests and allow override",
          "is_bot": false,
          "headline": "Merge pull request #25 from Yolean/gatewayapi-reduce-default-resource…",
          "author_name": "solsson",
          "author_login": "solsson",
          "committed_at": "2026-05-12T08:16:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "da717f99953c433d743b2b9ec7b9c8807e624972",
          "body": "List containerd's images: images list --context=<ctx>",
          "is_bot": false,
          "headline": "Merge pull request #24 from Yolean/images-list-from-cluster",
          "author_name": "solsson",
          "author_login": "solsson",
          "committed_at": "2026-05-12T08:14:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9e493bc6424701e55e7533e8e75f4efdae63d522",
          "body": "…e requests\n\nUpstream Envoy Gateway ships with 100m/256Mi controller and\n100m/512Mi data-plane proxy requests, which oversubscribe a\n2GB-RAM appliance node and hurt single-user dev clusters\nthat never push the proxy past idle.\n\nTwo new config knobs under gateway.resources.{controller,proxy}:\neach ta\n[…]\n\non top -- EG honours the latest reconciled spec.\n\nWire-through: docker, qemu, multipass providers all pass\ncfg.Gateway.Resources.{Controller,Proxy} to envoygateway.Install.\n\nSchema files regenerated.",
          "is_bot": false,
          "headline": "feat(provision/envoygateway): configurable controller + proxy resourc…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-12T08:12:00Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "550f3190a2ba8bbbc48729855ea76f5918eb5485",
          "body": "`y-cluster images list` overloads to read from a cluster's\nk8s.io containerd namespace. Mutually exclusive with the\npositional YAML input -- same conceptual question\n(\"what images are in this scope?\"), different source.\n\nOutput is one row per stored manifest (digest-aliases of\nthe same content fold \n[…]\n else. Hostport \":port\" before the last slash\nisn't counted as a tag (the standard containerd-ref edge\ncase stripTag already handles).\n\nRefs specs/y-cluster/FEATURE_REQUEST_IMAGES_LIST_FROM_CLUSTER.md",
          "is_bot": false,
          "headline": "feat(images): list --context=<ctx> queries the cluster's containerd",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-12T07:55:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "51697d783d2420abb00c8950a3dc3d0bdf314bb1",
          "body": "Fix image load issue with digest only",
          "is_bot": false,
          "headline": "Merge pull request #23 from Yolean/images-load-config-digest-refs",
          "author_name": "solsson",
          "author_login": "solsson",
          "committed_at": "2026-05-11T19:31:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e22775ae9fd64c8868ffdb4420e8558014a207ac",
          "body": "Two changes in the post-import alias step:\n\n1. The alias loop walked every new row from `ctr image list`,\n   including the bare `sha256:<hex>` config-digest row that ctr\n   writes alongside the canonical ref. stripTag turned that into\n   the literal \"sha256\", and the synthesized alias became\n   \"sha\n[…]\nin\nTestAliasFor. Summary log filters the config-digest row too, so\noperators no longer see misleading \"imported sha256:...\" lines.\n\nRefs specs/y-cluster/ISSUE_IMAGES_LOAD_MANGLES_CONFIG_DIGEST_REFS.md",
          "is_bot": false,
          "headline": "fix(images): skip config-digest rows, alias digest-only inputs",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-11T18:15:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3a4b0a1e557b599e175c2b1d107926f0e98a8fff",
          "body": null,
          "is_bot": false,
          "headline": "an attempt to get readable log lines for images load",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-11T08:26:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5129b0c12bdadcc3aada50d92347411f84de4316",
          "body": "Support remote images with images load subcommand",
          "is_bot": false,
          "headline": "Merge pull request #22 from Yolean/images-cache-support-remote",
          "author_name": "solsson",
          "author_login": "solsson",
          "committed_at": "2026-05-11T08:09:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fc238ef357450bd087bc4c83e81a5071a212134b",
          "body": "…present\n\n`y-cluster images load` accepts:\n\n  ./...  /...  ~/...      treat as local path\n                          - file: an already-tarred OCI archive\n                          - directory: an OCI v1 layout (tar\n                            streamed on the fly, equivalent to\n                      \n[…]\n stdin and path input is asserted before any kubeconfig is\n  consulted (so misuse errors don't get masked by a missing\n  context).\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(images): load <ref|path|-> -- ref support, cache reuse, skip-if-…",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-11T08:02:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c85c79648cd71a762bbf7bf7d86207908b6fd28c",
          "body": "Appliance primitives followup",
          "is_bot": false,
          "headline": "Merge pull request #21 from Yolean/appliance-primitives-followup",
          "author_name": "solsson",
          "author_login": "solsson",
          "committed_at": "2026-05-07T10:12:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5ada0ce3b84baeb9f429014c5d326544edeb9218",
          "body": "Previously teardown unconditionally logged \"teardown complete,\ndisk and keypair deleted\" regardless of what actually\nhappened. The os.Remove calls swallowed all errors (including\nIsNotExist) with `_ =`, so a teardown against an already-empty\ncache dir -- common after prepare-export consumed the qcow\n[…]\nract via\nzaptest/observer: empty-cache must NOT claim deletion; a cache\nwith disk + keypair must list both in the `removed` field.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(provision/qemu): teardown logs reflect actual file ops",
          "author_name": "Yolean k8s-qa",
          "author_login": null,
          "committed_at": "2026-05-07T09:43:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        }
      ],
      "releases_count": 20,
      "commits_last_year": 181,
      "latest_release_at": "2026-07-13T12:07:45Z",
      "latest_release_tag": "v0.5.0",
      "releases_from_tags": false,
      "days_since_last_push": 8,
      "active_weeks_last_year": 6,
      "days_since_latest_release": 8,
      "mean_days_between_releases": 7.8
    },
    "community": {
      "has_readme": true,
      "has_license": false,
      "has_description": false,
      "has_contributing": false,
      "health_percentage": 25,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "github.com/Yolean/y-cluster",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/Yolean/y-cluster",
          "is_deprecated": false,
          "latest_version": "v0.5.0",
          "repository_url": "https://github.com/Yolean/y-cluster",
          "versions_count": 20,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-13T12:07:05Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 8
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 0,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_stars": 0
      },
      "open_issues_and_prs": 2
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "example"
      ],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 40587,
      "source_files_sampled": 211,
      "oversized_source_files": 0,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "go.mod"
      ],
      "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": [
        "go"
      ],
      "dependencies": [
        {
          "name": "cuelang.org/go",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.16.1"
        },
        {
          "name": "github.com/containerd/errdefs",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.0.0"
        },
        {
          "name": "github.com/google/go-containerregistry",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.21.5"
        },
        {
          "name": "github.com/hetznercloud/hcloud-go/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.39.0"
        },
        {
          "name": "github.com/invopop/jsonschema",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.14.0"
        },
        {
          "name": "github.com/moby/moby/api",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.54.2"
        },
        {
          "name": "github.com/moby/moby/client",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.4.1"
        },
        {
          "name": "github.com/pkg/sftp",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.13.10"
        },
        {
          "name": "github.com/spf13/cobra",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.10.2"
        },
        {
          "name": "go.uber.org/zap",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.27.1"
        },
        {
          "name": "golang.org/x/crypto",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.54.0"
        },
        {
          "name": "sigs.k8s.io/kustomize/api",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.21.1"
        },
        {
          "name": "sigs.k8s.io/kustomize/kyaml",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.21.1"
        },
        {
          "name": "sigs.k8s.io/yaml",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.6.0"
        }
      ],
      "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": 25,
        "open_issues": 2,
        "closed_ratio": 0.333,
        "closed_issues": 1,
        "closed_unmerged_prs": 2
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "solsson",
          "commits": 41,
          "avatar_url": "https://avatars.githubusercontent.com/u/144945?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yaml",
        "e2e-release.yaml",
        "mirror-k3s.yaml"
      ],
      "has_docs_dir": false,
      "linter_configs": [
        ".golangci.yaml"
      ],
      "has_editorconfig": false,
      "has_linter_config": true,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "go.sum"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "1 out of 1 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": 0,
            "reason": "Found 0/1 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 0,
            "reason": "project has 0 contributing companies or organizations -- score normalized to 0",
            "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": 0,
            "reason": "no 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": 10,
            "reason": "all dependencies are pinned",
            "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": 0,
            "reason": "Project has not signed or included provenance with any releases.",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 8,
            "reason": "2 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "6e7b7132b6641f3a831f0fe134baa698a6017df5",
        "ran_at": "2026-07-22T11:02:09Z",
        "aggregate_score": 3.9,
        "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-20T09:17:03Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-13T12:07:05Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 9,
          "created_at": "2026-05-01T04:38:23Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 11,
          "created_at": "2026-05-01T04:55:32Z",
          "last_comment_at": "2026-05-07T11:03:49Z",
          "last_comment_author": "solsson"
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/Yolean/y-cluster",
    "host": "github.com",
    "name": "y-cluster",
    "owner": "Yolean"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 50,
      "inputs": {
        "security": 38,
        "vitality": 73,
        "community": 12,
        "governance": 51,
        "engineering": 66
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 73,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 61,
            "inputs": {
              "commits_last_year": 181,
              "human_commit_share": 1,
              "days_since_last_push": 8,
              "active_weeks_last_year": 6
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 8 days ago",
                "points": 28.8,
                "status": "partial",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 8
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "6/52 weeks with commits",
                "points": 4.2,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 6
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "181 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 181
                    }
                  }
                ],
                "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": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "releases_count": 20,
              "latest_release_tag": "v0.5.0",
              "releases_from_tags": false,
              "days_since_latest_release": 8,
              "mean_days_between_releases": 7.8
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "20 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 20
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 8 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 8
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~7.8 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 7.8
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 12,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "forks": 0,
              "stars": 0,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "0 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "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": "critical",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 25,
            "inputs": {
              "has_readme": true,
              "has_license": false,
              "has_contributing": false,
              "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": 0,
                "status": "missed",
                "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": "moderate",
        "name": "Sustainability & Governance",
        "value": 51,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "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 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "moderate",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 51,
            "inputs": {
              "merged_prs": 25,
              "open_issues": 2,
              "closed_issues": 1,
              "issue_closed_ratio": 0.333,
              "closed_unmerged_prs": 2
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "33% of issues closed",
                "points": 15.6,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 33
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "25/27 decided PRs merged",
                "points": 35.4,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 25,
                      "decided": 27
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/1 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 62,
            "inputs": {
              "followers": 9,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "Yolean",
              "public_repos": 99,
              "account_age_days": 4165
            },
            "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": "9 followers of Yolean",
                "points": 7.2,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 9,
                      "login": "Yolean"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "99 public repos, account ~11 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 99
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 11
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/Yolean/y-cluster"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 8
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on go",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "go"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 8 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 8
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "20 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 20
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 66,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "good",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 84,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": true,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "3 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "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": ".golangci.yaml",
                "points": 16,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".golangci.yaml"
                    }
                  }
                ],
                "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": "1 out of 1 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "at_risk",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 0,
                "status": "missed",
                "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": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 38,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Packaging. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "packaging"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 38,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 17,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 1,
              "scorecard_aggregate": 3.9
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "1 out of 1 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 0/1 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "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": "no update tool detected",
                "points": 0,
                "status": "missed",
                "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": "all dependencies are pinned",
                "points": 5,
                "status": "met",
                "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": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "2 existing vulnerabilities detected",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 68,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.93,
              "agent_instruction_files": [],
              "agent_instruction_max_bytes": null
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "no CLAUDE.md / AGENTS.md / editor rules",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_instructions",
                    "params": {}
                  }
                ],
                "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": "93 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 93,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "excellent",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 87,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [],
              "agent_commit_share": 0.77,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "go.mod (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "go.mod"
                    }
                  }
                ],
                "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": ".golangci.yaml",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".golangci.yaml"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "Go (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "77 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 77,
                      "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": "all dependencies are pinned",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 40587,
              "source_files_sampled": 211,
              "oversized_source_files": 0
            },
            "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": "0/211 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 211,
                      "oversized": 0
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "at_risk",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "example_dirs": [
                "example"
              ],
              "has_mcp_signal": false,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "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": "example",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "example"
                    }
                  }
                ],
                "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": [
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-22T11:02:26.067426Z",
  "schema_version": "0.26.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/y/Yolean/y-cluster.svg",
  "full_name": "Yolean/y-cluster",
  "license_state": "absent",
  "license_spdx": null
}

Las puntuaciones son señales, no garantías. Reflejan prácticas públicamente visibles en GitHub; no son una auditoría de código ni una garantía de seguridad.

Los datos ausentes se excluyen y los pesos se renormalizan; nunca se puntúan como cero. La metodología es versionada y abierta: métricas v1.13.0, esquema v0.26.0 — metodología completa · wiki de métricas.

Cómo se sitúa un resultado dentro del registro general: estadísticas agregadasGo.