JSON-Rohbericht maschinenlesbar
{
"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
}