tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

kubectl: el vigía nuevo señaló dos inertes y esto los enciende — 46 → 44

`kubectl-neat` y `kubectl-tree` llevaban meses sellados y **no se podían invocar**: los dos son
subcomandos que despacha `kubectl`, y `kubectl` no estaba en el catálogo. Probado, no supuesto —
`kubectl plugin list` con los dos artefactos en el PATH los lista a los dos.

`kubectl version --client -o json` contesta con todos los campos poblados (gitVersion v1.37.0,
gitCommit, gitTreeState clean, goVersion go1.26.4). REPRODUCE bit a bit.

Los `-X` del ldflags no son adorno: sin ellos `kubectl version` dice `v0.0.0-master+$Format:%H$`, y
un cliente de k8s NEGOCIA por versión — varios comandos avisan de desfase cliente/servidor
comparando exactamente esos campos. Los nombres son los de `hack/lib/version.sh` de upstream, para
no inventar un esquema paralelo.

**Uno de esos campos era una trampa de reproducibilidad**: `buildDate`, que upstream llena con
`date -u` ⇒ dos builds del mismo fuente darían binarios distintos (la familia del sello de nftables
y del `BUILD_ID` de valkey). Se resuelve como lo resuelve upstream, leyendo `SOURCE_DATE_EPOCH`, que
el lab exporta con valor FIJO. Sale `1970-01-01T00:00:01Z` — feo y CONSTANTE, que es lo que importa.

`gitCommit` va pineado a mano porque el tarball no trae `.git`. ⚠ El tag `v1.37.0` es ANOTADO: el
`git/ref` devuelve el sha del OBJETO TAG, no el del commit, y quedarse con ése habría horneado un
sha que no es ningún commit. Hay que resolver tag → commit.

⚠ **Y un hallazgo lateral que dejo anotado en la receta porque no es de esta receta:** el árbol de
k8s trae su propio `vendor/` curado, pero el lab corre `go mod vendor` en el FETCH siempre que haya
`go.mod`, sin mirar si el proyecto ya traía uno (`vendor_go_deps`, incondicional — se ve en el log:
`go: downloading …` ANTES de `configure`). O sea que se compila el vendor REGENERADO, no el de
upstream. Acá salió bien y reproduce, pero es la misma figura que el clobber del `vendor/` de Cargo,
que sí necesitó un campo de receta para resolverse.

2546f5cdf83b0f5fc2d803151ccfdcba74557afc · by Sergio · (1 month ago) · parent 6fa955f29 · browse the tree at this commit

Semantic delta

No definition changed: this change is text, documentation or data.

3 files · +97 −7

diff --git a/docs/state/build-state.json b/docs/state/build-state.json
index c1e1c001..6761da29 100644
--- a/docs/state/build-state.json
+++ b/docs/state/build-state.json
@@ -1,15 +1,15 @@
 {
  "schema": "hammer-build-state/1",
  "totals": {
-  "recipes": 884,
-  "nodes": 886,
-  "sealed": 884,
+  "recipes": 885,
+  "nodes": 887,
+  "sealed": 885,
   "ajeno": 2
  },
  "by_class": {
   "ajeno": 2,
   "c": 241,
-  "go": 362,
+  "go": 363,
   "gui": 41,
   "kernel": 6,
   "rust": 234
@@ -17,7 +17,7 @@
  "debt_by_class": {},
  "by_queue": {
   "corpus": {
-   "sealed": 884,
+   "sealed": 885,
    "ajeno": 2
   }
  },
@@ -43,7 +43,7 @@
    "sealed": 101
   }
  },
- "sin_perfil": 646,
+ "sin_perfil": 647,
  "orphan_deps": [],
  "topo_ok": true,
  "nodes": {
@@ -5887,7 +5887,7 @@
     "escritorio-sway",
     "servidor"
    ],
-   "dependientes_total": 362
+   "dependientes_total": 363
   },
   "go-callvis": {
    "iname": "go-callvis",
@@ -8760,6 +8760,24 @@
    "perfiles": [],
    "dependientes_total": 0
   },
+  "kubectl": {
+   "iname": "kubectl",
+   "version": "1.37.0",
+   "link": "static",
+   "compiler": "zig-cc",
+   "deps": [
+    "go"
+   ],
+   "cls": "go",
+   "queue": "corpus",
+   "foreign": false,
+   "hash": "b3:ca95c5292688c838715727f9b909a0722d9fc98a778edefb2a4864e01678056e",
+   "state": "sealed",
+   "blocked_by": [],
+   "unblocks": 0,
+   "perfiles": [],
+   "dependientes_total": 0
+  },
   "kubectl-neat": {
    "iname": "kubectl-neat",
    "version": "2.0.3",
diff --git a/docs/state/repro-verificado.tsv b/docs/state/repro-verificado.tsv
index ff8b05ba..0887218c 100644
--- a/docs/state/repro-verificado.tsv
+++ b/docs/state/repro-verificado.tsv
@@ -78,3 +78,4 @@ cronie	387347b89b107d97febbb2692ce2d292e74bc7b1fba105676befe396cc3ebf21	2026-09-
 valkey	9571c1a691ff8dd2e91611a341d2ddab11a9cc9a030ed8054006a4626542a06f	2026-09-11	reproduce
 abseil-cpp	a0d2ad6f771ecb64471a7e25db365cfcfb785574d75d4161ee2423beb7f35b5f	2026-09-11	reproduce
 protobuf	c01f39d4a566e48f09d077ac20a5c6249c6a36fe3c53196c1c6e5e4ce0bc5991	2026-09-11	reproduce
+kubectl	ca95c5292688c838715727f9b909a0722d9fc98a778edefb2a4864e01678056e	2026-09-11	reproduce
diff --git a/recipes/kubectl.toml b/recipes/kubectl.toml
new file mode 100644
index 00000000..cbd9dfb6
--- /dev/null
+++ b/recipes/kubectl.toml
@@ -0,0 +1,71 @@
+# kubectl 1.37.0 — el cliente de Kubernetes. Entra por un hallazgo del vigía nuevo
+# (`scripts/vigia-subcomandos.py`): el catálogo tenía `kubectl-neat` y `kubectl-tree` SELLADOS y
+# **inertes**, porque los dos son subcomandos que despacha `kubectl` y `kubectl` no estaba. Es la
+# misma figura que `protoc-gen-go` sin `protoc`: cuatro indicadores en verde —contenido, sonames,
+# grafo, reproducibilidad— sobre binarios que no se pueden invocar.
+#
+# `GOFLAGS=-mod=vendor GOPROXY=off` dentro del sandbox: la fase de compile NO toca la red, usa el
+# `vendor/` y punto. `go 1.26.0` pide el `go.mod`; el corpus tiene `go` 1.26.4 ⇒ entra.
+# `GOTOOLCHAIN=local` para que Go NO se descargue otro toolchain si algún día el `go.mod` pidiera uno
+# más nuevo: eso sería red dentro del sandbox y una entrada fuera del hash.
+#
+# ⚠ **OJO CON DE DÓNDE SALE ESE `vendor/`, porque NO es el que trae el tarball.** El árbol de k8s
+# publica su propio `vendor/` curado, pero el lab corre `go mod vendor` en el FETCH —host-side, antes
+# del sandbox— siempre que haya un `go.mod`, sin mirar si el proyecto ya traía uno
+# (`takana-build::fetch::vendor_go_deps`, incondicional). Se ve en el log: `go: downloading …`
+# ANTES de la fase `configure`. O sea que el `vendor/` que se compila es el REGENERADO.
+#
+# Acá salió bien —`go.sum` pinea el contenido y la receta REPRODUCE bit a bit, verificado— pero es
+# la misma figura que el clobber del `vendor/` de Cargo, que sí tuvo que resolverse con un campo de
+# receta (`cargo_vendor_dir`). Queda anotado: si algún día una receta Go depende de un `vendor/`
+# PARCHEADO por upstream, el lab se lo va a pisar en silencio.
+#
+# ⚠ **LOS `-X` NO SON COSMÉTICOS Y UNO DE ELLOS ES UNA TRAMPA DE REPRODUCIBILIDAD.** Sin ellos
+# `kubectl version` contesta `v0.0.0-master+$Format:%H$`, que es peor que inútil: un cliente de k8s
+# NEGOCIA con el servidor por versión, y varios comandos avisan de desfase cliente/servidor
+# comparando estos valores. Los nombres y el formato son los que usa el propio `hack/lib/version.sh`
+# de upstream, para no inventar un esquema paralelo.
+#
+# El de la trampa es `buildDate`: upstream lo llena con `date -u` ⇒ **dos builds del mismo fuente
+# darían binarios distintos**, la familia exacta del sello de tiempo de nftables y del `BUILD_ID` de
+# valkey. Upstream ya previó el caso y su script respeta `SOURCE_DATE_EPOCH`; acá se hace lo mismo,
+# y el lab exporta esa variable con un valor FIJO (`1`), así que la fecha sale constante.
+#
+# `gitCommit` va pineado a mano porque el tarball de release NO trae `.git` y no hay de dónde
+# sacarlo: es el commit al que apunta el tag `v1.37.0` (el tag es ANOTADO, así que hay que resolver
+# el objeto tag → commit; quedarse con el sha del tag daría un valor que no es ningún commit).
+# `gitTreeState=clean` es verdad: se construye desde un tarball de release intacto.
+name    = "kubectl"
+version = "1.37.0"
+license = "Apache-2.0"
+
+[source]
+tarball = "https://github.com/kubernetes/kubernetes/archive/refs/tags/v1.37.0.tar.gz"
+sha256  = "956ddae3b12acc08a715aea0411a168a36d5989b3e7185deeb6bf46b7dac19cf"
+
+[build]
+compiler = "zig-cc"   # inerte (Go no usa zig); el toolchain real llega por deps.build
+target   = "x86_64-linux-musl"
+link     = "static"
+
+[deps]
+build = ["go"]
+
+[build.phases]
+configure = "true"
+compile = '''
+export GOCACHE=/tmp/gocache GOPATH=/tmp/gopath GOTOOLCHAIN=local CGO_ENABLED=0 GOFLAGS=-mod=vendor GOPROXY=off
+V=k8s.io/component-base/version
+C=k8s.io/client-go/pkg/version
+FECHA=$(date -u -d "@${SOURCE_DATE_EPOCH:-1}" +%Y-%m-%dT%H:%M:%SZ)
+COMMIT=f54c212e3a2f75d674b717a9b29052b20b60aefc
+go build -trimpath -ldflags "-buildid= -s -w \
+  -X $V.gitVersion=v1.37.0 -X $C.gitVersion=v1.37.0 \
+  -X $V.gitMajor=1 -X $C.gitMajor=1 \
+  -X $V.gitMinor=37 -X $C.gitMinor=37 \
+  -X $V.gitCommit=$COMMIT -X $C.gitCommit=$COMMIT \
+  -X $V.gitTreeState=clean -X $C.gitTreeState=clean \
+  -X $V.buildDate=$FECHA -X $C.buildDate=$FECHA" \
+  -o /out/usr/bin/kubectl ./cmd/kubectl
+'''
+install = "true"