Source document
Alojamiento: la organización PBSWORK como fuente canónica
Spanish text, transcribed from the repository. The unformatted
source is
hosting.md.
Qué ocurrió
La cuenta de GitHub PBSWORK-ORG quedó marcada (flagged) por el sistema antispam de GitHub. El síntoma es un fallo silencioso: la cuenta y todos sus repositorios pasan a devolver 404 a usuarios no autenticados, sin correo, sin aviso y sin entrada en el panel.
Lo insidioso es que el dueño es la única persona que no ve el 404. Con sesión iniciada todo funciona con normalidad, así que el repositorio parece público mientras está invisible para el mundo. Un enlace compartido en una respuesta, un paper o un LLM que lo citó deja de resolver, y no hay forma de enterarse salvo comprobándolo a propósito.
La decisión: mover el repositorio a la organización
La hipótesis de partida era que el flag afecta a la cuenta y no al contenido, así que bastaba con sacar el repositorio de la cuenta marcada y ponerlo bajo la organización PBSWORK (id 198443207, creada en 2025). Se verificó con PBSWORK/MESH_SILOS, que respondía 200 sin credenciales en ese momento.
Movimiento ejecutado (resultado real, no el previsto):
| Antes | Después |
|---|---|
github.com/PBSWORK-ORG/HECATE (404 público) | github.com/PBSWORK/HECATE (404 público) |
| Cuenta personal marcada | Organización también oculta a invitados |
Remoto origin con el owner antiguo | git@github.com:PBSWORK/HECATE.git |
El nombre del repositorio no cambia, así que la URL final es github.com/PBSWORK/HECATE. Al no aceptar GitHub la transferencia, el contenido se replicó con git push: se conservan historial, etiquetas y releases, pero no los metadatos del panel (issues, PRs, estrellas) del repositorio original.
Importante: para trabajar, el flag es irrelevante. El titular, con sesión iniciada, crea repositorios, hace push, etiqueta, abre issues y ve todo con normalidad. La marca solo afecta a la visibilidad anónima, es decir, a cualquiera que abra la URL sin sesión. Por eso el repositorio es completamente funcional como entorno de desarrollo; lo que queda pendiente es que un desconocido pueda verlo.
Por qué no Codeberg
Una revisión anterior de este documento proponía Codeberg como fuente canónica. No se usó nunca: no existe cuenta ni remoto allí, y el titular solo tiene cuenta de GitHub. La propuesta se retiró de todos los metadatos (CITATION.cff, .well-known/ai.txt, llms.txt) para no publicar enlaces que no resuelven. Si algún día se añade un espejo, se decidirá con una cuenta real y se documentará aquí antes de tocar los enlaces.
Estado actual (honesto)
| Paso | Estado |
|---|---|
| 1. Todo el trabajo publicado en el remoto antiguo antes de mover nada | hecho (git push origin main --tags) |
2. Transferencia PBSWORK-ORG/HECATE → PBSWORK/HECATE desde los ajustes | rechazada por GitHub: 422 · Repository transfers not available for this account. Una cuenta marcada no puede transferir. |
| 3. Alternativa ejecutada: repositorio vacío creado en la organización | hecho (PBSWORK/HECATE, público) |
| 4. Historial y etiquetas empujados a la organización | hecho: 24 commits y v0.3.0–v0.6.0 verificados con git ls-remote |
5. Remoto origin apuntando a la organización | hecho (git@github.com:PBSWORK/HECATE.git) |
6. Enlaces públicos a github.com/PBSWORK/HECATE | hecho en site/, pyproject.toml, Cargo.toml, CITATION.cff, .well-known/ai.txt y llms.txt |
| 7. Comprobación sin credenciales de que la URL nueva resuelve | devuelve 404, que es el comportamiento esperado mientras la cuenta esté marcada |
| 8. Apelación del flag en GitHub Support | pendiente, lo abre el titular de la cuenta |
Estado del flag en 1.1.0 (2026-10-23)
Sigue marcada. No se ha apelado desde el agente y no se debe hacer: la apelación la abre el titular de la cuenta, con su identidad, desde GitHub Support. Un agente que enviara esa solicitud estaría hablando en nombre de una persona ante el sistema antispam de GitHub.
Consecuencia práctica, sin cambios: el desarrollo funciona entero con sesión iniciada; lo que no funciona es la audiencia sin sesión. Por eso docs/release-1.0.0.md y docs/benchmarks/final.md existen como documentos del repositorio y no sólo como páginas web: si nadie anónimo puede ver el sitio, los números tienen que poder leerse en el árbol.
Los ocho enlaces canónicos siguen apuntando a github.com/PBSWORK/HECATE. No se ha cambiado ninguno a la organización antigua.
Por qué el 404 anónimo no bloquea el trabajo
Mover el repositorio a la organización no ha cambiado la visibilidad anónima. Comprobado sin credenciales, después del traslado:
| Consulta anónima | Resultado |
|---|---|
api.github.com/orgs/pbswork/repos | 200 y lista PBSWORK/HECATE y PBSWORK/MESH_SILOS como public |
api.github.com/repos/PBSWORK/HECATE | 404 |
github.com/PBSWORK/HECATE | 404 |
github.com/PBSWORK (página de la organización) | 404 |
github.com/PBSWORK/MESH_SILOS | 404 — respondía 200 minutos antes del traslado |
github.com/rust-lang/rust (control) | 200 |
Proxy externo sobre github.com/PBSWORK/HECATE | 404, confirmado desde otra red |
La API de la organización sigue describiendo los repositorios como públicos mientras la web los oculta a los visitantes sin sesión. La consecuencia práctica es que el flag viaja con la identidad: cualquier namespace del titular, incluida la organización, queda oculto a guests. Crear el repositorio nuevo no lo empeoró de forma demostrable, pero tampoco lo arregló, y la hipótesis de que el flag era solo de la cuenta personal no se sostuvo.
Con sesión iniciada todo funciona: crear repositorios, push, etiquetas, issues y la web del proyecto. El flag no limita el desarrollo, solo la audiencia. Ese es el motivo por el que este detalle se documenta y no se trata como un bloqueante.
Lo que sí está resuelto, y no es poco: el contenido ya no vive en un único sitio. El historial completo, las cuatro etiquetas y el árbol de trabajo están replicados en un namespace distinto del marcado. La apelación deja de ser urgente para no perder trabajo.
Ningún script de este repositorio finge que la migración está hecha. just links reporta como no resolubles las URL que no responden, que es la verdad.
Detalle importante de orden: publicar antes de mover. Si se traslada con commits locales sin publicar, se pierden si algo sale mal; publicados, el traslado no puede llevarse por delante nada que no esté ya replicado.
Cómo se hizo el traslado
git push origin main --tagscontra el remoto antiguo, para que nada quedara solo en local.- Settings → Danger Zone → Transfer ownership con destino
PBSWORK. GitHub lo rechazó con422: una cuenta marcada no puede transferir. - Alternativa: crear
PBSWORK/HECATEvacío (público, sin README ni licencia) desde la organización. git remote set-url origin git@github.com:PBSWORK/HECATE.gitgit push -u origin mainygit push origin --tags.
Consecuencia de la alternativa: se conserva el 100 % del historial, pero no los metadatos del panel (issues, PRs, estrellas) del repositorio original. Y, como queda documentado arriba, la visibilidad anónima sigue dependiendo de la apelación.
Si la apelación no prospera
Un alojamiento cuyo modo de fallo es invisible no puede ser la única fuente pública. Las opciones, en orden de coste:
- Apelar (
Account Questions→Appeal a flagged account). Es lo primero y lo único que devuelve la visibilidad anónima a la normalidad. - Espejo en otra forja con una cuenta distinta de la marcada. Requiere crear esa cuenta; hasta entonces no se anunciará ningún enlace, porque un espejo que no existe es peor que ninguno.
- Publicación de artefactos por otra vía: el sitio en
hecateforge.com(Cloudflare, no depende de GitHub) y los binarios como artefactos de release alojados fuera del repositorio.
La tercera vía ya está en marcha
El sitio se publica en Cloudflare Pages y ya sirve https://hecateforge.com sin pasar por GitHub: es la única pieza del proyecto que hoy es visible sin sesión y sin depender del flag. El manual de operación —despliegue, dominio, cabeceras y lo que queda pendiente— está en docs/hosting-cloudflare.md. Consecuencia práctica: mientras el flag dure, la web es el canal público y el repositorio es documentación de trabajo, no la cara del proyecto.
Publicar a partir de ahora
El remoto ya es la organización, así que cada release se publica una sola vez:
just audit # la verificación de siempre
git tag -a v0.8.0 -m "v0.8.0 — ..."
git push origin main --tags
Comprobar con git remote -v que origin sigue en PBSWORK antes de etiquetar. Si alguien restaura el remoto antiguo por error, las etiquetas acabarían en el namespace marcado.
Lista de comprobación de publicación
Se recorre entera antes de cada push que publique algo, y se copia el resultado en el CHANGELOG. No es burocracia: el modo de fallo de este alojamiento es invisible, así que lo único que lo detecta es comprobarlo a propósito.
| # | Comprobación | Comando | Criterio |
|---|---|---|---|
| 1 | Árbol limpio, sin cambios ajenos mezclados | git status --porcelain | vacío |
| 2 | El remoto apunta a la organización | git remote -v | PBSWORK/HECATE, no PBSWORK-ORG |
| 3 | Los commits que se publican son los previstos | git log --oneline origin/main..HEAD | sólo los de esta publicación |
| 4 | La suite pasa en local | just check | verde |
| 5 | La auditoría de repositorio pasa | just audit | verde |
| 6 | Los fixtures de paridad están al día | just fixture | --check sin diferencias |
| 7 | La versión es la misma en los cinco sitios | just versions | Cargo.toml, pyproject.toml, CITATION.cff, llms.txt, package.json |
| 8 | La etiqueta es anotada y describe el cambio | git tag -a vX.Y.Z -m "..." | git cat-file -t responde tag |
| 9 | Publicar antes de mover nada | git push origin main --tags | git ls-remote --tags origin lista la nueva |
| 10 | Los enlaces públicos resuelven sin sesión | just links | 2xx/3xx en todos |
| 11 | El nombre del repositorio no depende de la persona que empuja | curl -s -o /dev/null -w '%{http_code}' https://github.com/PBSWORK/HECATE | 2xx cuando el flag esté resuelto; 404 mientras no lo esté, y se reporta como tal |
Los pasos 1–7 y 11 son los que evitan los cuatro fallos que ya han ocurrido en este proyecto: mezclar trabajo ajeno en un commit de release, etiquetar contra el remoto equivocado, publicar con los fixtures desactualizados y una versión distinta en cada metadato.
El nombre canónico no se negocia
PBSWORK/HECATE es el repositorio, y no se cambia. El remoto origin de todos los clones apunta ahí (git@github.com:PBSWORK/HECATE.git), los cinco metadatos lo declaran (Cargo.toml, pyproject.toml, CITATION.cff, .well-known/ai.txt, llms.txt) y el sitio enlaza ahí. Cualquier herramienta o panel que muestre otro propietario describe un estado transitorio del cliente, no una decisión del proyecto: la respuesta es comprobar con git remote -v, no reescribir URLs.
Mover los enlaces a otro namespace para que una comprobación salga en verde sería el peor cambio posible: rompería el remoto, la citación y los enlaces del sitio a la vez para satisfacer a una herramienta. Si algún día hay que cambiar de propietario, se hace como una migración —documentada aquí, con el contenido replicado y verificado antes de tocar un solo enlace— y no como un ajuste de texto.
Nota de estado (2026-10-23)
La comprobación anónima del paso 11 sigue devolviendo 404 en github.com/PBSWORK/HECATE y en github.com/PBSWORK/HECATE/releases, mientras la API de la organización lista el repositorio como público. Es el comportamiento descrito arriba: el flag oculta el namespace a los visitantes sin sesión aunque el contenido sea público. Se reporta como está y no se "arregla" cambiando URLs.
El duplicado se retiró (2026-10-28)
github.com/PBSWORK-ORG/HECATE ya no existe: el titular lo borró el 2026-10-28. La comprobación de que no se perdía nada se hizo antes de retirarlo, y se repite aquí porque es el motivo por el que el borrado fue seguro:
| Comprobación | Resultado tras el borrado |
|---|---|
git ls-remote https://github.com/PBSWORK-ORG/HECATE.git | falla: el repositorio ya no existe |
git ls-remote origin refs/heads/main | 67a3668, la release actual |
git rev-parse HEAD en este clon | 67a3668, el mismo commit |
git merge-base --is-ancestor db0bbe7 HEAD | sí — el último commit del duplicado estaba contenido |
etiquetas v* en PBSWORK/HECATE | 27 publicadas; 28 en local, porque v1.9.0-final es local a propósito |
El duplicado tenía una sola rama main en db0bbe7 —«mueve el owner canónico a la organización»— y ninguna etiqueta v2.x: era el original que se replicó, no una copia que recibiera trabajo. Por eso git merge-base --is-ancestor db0bbe7 HEAD respondía que sí, y borrarlo no perdió ni un commit. refs/heads/main en PBSWORK/HECATE siguió en la release actual durante todo el proceso.
La vía reversible que documentaba esta sección —*Archive this repository* en lugar de Delete— ya no aplica: el repositorio está eliminado. Si alguna vez hay que volver al estado anterior, el contenido está en PBSWORK/HECATE, que es el canónico y el único remoto.
Una consecuencia que conviene tener presente: git ls-remote contra el namespace borrado ahora falla. La asimetría que se documentaba aquí —el protocolo git servía el namespace marcado aunque la web diera 404— sólo era válida mientras el repositorio existía, así que ya no sirve como forma de auditar el namespace de la cuenta personal sin credenciales.
Sobre Codeberg
No queda ninguna URL a Codeberg: ni en el código, ni en los metadatos, ni en el sitio. La comprobación es git grep -rn 'codeberg\.', que no devuelve nada —git grep -ri codeberg sí devuelve estas líneas y las del CHANGELOG, que son la explicación de por qué no se usó, no un enlace—. Las menciones originales se retiraron en la fase 7. La regla vigente es: GitHub es el único remoto, y el nombre canónico es github.com/PBSWORK/HECATE hasta que la comprobación del paso 11 diga otra cosa.
Auto-auditoría mensual
El fallo es silencioso, así que hay que comprobarlo a propósito. Desde una sesión no autenticada —ventana privada, o curl sin credenciales— los enlaces deben resolver:
just links
# o a mano:
curl -s -o /dev/null -w '%{http_code}\n' https://github.com/PBSWORK/HECATE
curl -s -o /dev/null -w '%{http_code}\n' https://hecateforge.com
scripts/check_hosting_links.py automatiza esto: recorre los enlaces públicos declarados en llms.txt, ai.txt, CITATION.cff y README.md, los pide sin credenciales y falla si alguno no responde 2xx/3xx. Detecta los tres casos que duelen:
- una cuenta o un repositorio marcado (404 en el canónico),
- un enlace a un destino que todavía no existe (404 en una migración a medias),
- un enlace interno que apunta a un fichero que ya no existe.
No está en just check ni en scripts/verify.sh porque necesita red: la regla del proyecto es que la verificación obligatoria funcione sin conexión. Es una tarea manual mensual, y la primera del mes.
Lección para el diseño
Un alojamiento con fallo silencioso obliga a tener un plan que no dependa de él:
- La fuente canónica no puede ser un servicio cuyo modo de fallo sea invisible.
- Un namespace marcado se abandona, no se espera: el contenido sano se muda a uno que no lo esté.
- Todo enlace público debe ser comprobable sin la sesión del dueño; si no, no hay auditoría posible.
- El proyecto debe seguir siendo verificable y clonable sin su forja: de ahí que la verificación sea local y que los metadatos (
CITATION.cff,llms.txt) viajen en el propio repositorio y no en un panel externo.