Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
129ec57
ci(release): deshabilitar attestations en publish-pypi para el camino…
complexluise Jun 25, 2026
9315a95
Merge pull request #147 from complexluise/fix/pypi-attestations-reusable
complexluise Jun 25, 2026
24bf5c5
Merge pull request #148 from complexluise/main
complexluise Jun 25, 2026
35099b1
docs(adr): 0037 — superficie CLI 0.10.0 (10 verbos agents-first que m…
complexluise Jun 27, 2026
726272b
feat(cli): status como mapa — next_best_action, readiness y preview p…
complexluise Jun 27, 2026
a8af1e5
docs(adr): 0038 — destino de los 5 verbos huérfanos del 0037 (10 verb…
complexluise Jun 27, 2026
214d230
feat(cli): --json unificado por decorador + B2G_JSON env + stdout pur…
complexluise Jun 27, 2026
c4aee24
feat(build): absorber networks via --spec + --scope/--min-weight + di…
complexluise Jun 27, 2026
d00fe8c
feat(cli): grupo noun-verb read {list,stats,show} absorbiendo inspect…
complexluise Jun 27, 2026
b66ac4a
feat(read): read top — centrales + co-citación con título (salida de …
complexluise Jun 27, 2026
46fd739
refactor(cli): curate como grupo noun-verb {dump,apply,accept,reject,…
complexluise Jun 28, 2026
8697144
feat(cli): maturity-stamp en artefactos one-shot (build/snapshot/read…
complexluise Jun 28, 2026
58ec4d1
test(resolve): paridad resolve vs seed --resolve (fuente única para #…
complexluise Jun 28, 2026
6541663
feat(chain): absorber monitor como chain --since (forrajeo incrementa…
complexluise Jun 28, 2026
f743ed4
refactor(cli): snapshot como grupo noun-verb {create, restore} (#163)…
complexluise Jun 28, 2026
df9fea2
feat(cli): absorber enrich en chain/build (#162) (#178)
complexluise Jun 28, 2026
b4f7123
refactor(cli): retirar verbo thesaurus, preservar capacidad como buil…
complexluise Jun 28, 2026
d4cdf0b
feat(cli): aliases de retrocompat con aviso de deprecación + entry-po…
complexluise Jun 28, 2026
fc7c9b6
docs(api): consolidar superficie CLI 0.10.0 + enmiendas ADR 0025/0031…
complexluise Jun 28, 2026
160a85c
test(e2e): capstone one-shot init→seed→chain→build→read guiado por re…
complexluise Jun 28, 2026
8d943f7
chore(proceso): bakear lecciones del epic 0.10.0 + comando /retro-cic…
complexluise Jun 28, 2026
272d87c
docs(notas): Nota 21 — descomposición de la suite de tests para poda …
complexluise Jun 28, 2026
fa76e25
test: poda de la suite — epic #184 (consolidación + retiro de duplica…
complexluise Jun 28, 2026
50a9f68
perf(test): eliminar build redundante en idempotencia de comunidades …
complexluise Jun 28, 2026
29b3f13
feat(skill): distribuir skill de Claude Code end-user vía `b2g skill …
complexluise Jun 28, 2026
9c81be8
feat(skill): salida agéntica explícita en `skill add` (ruta + cómo op…
complexluise Jun 28, 2026
fa19291
feat(cli)!: retirar la GUI local (api/SPA/b2g gui) — fuera del foco d…
complexluise Jun 28, 2026
c489064
fix(provenance): persistir manifest.enrichers vía enricher_log (#141)…
complexluise Jun 28, 2026
bc36b2c
docs: alinear docs vivos al presente de v0.10.0 (#191) (#199)
complexluise Jun 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions .claude/agents/coder.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,23 @@ todo verificable: otro agente (`verifier`) va a auditar tu diff.
- Lee `docs/API.md` (contrato), `docs/ARCHITECTURE.md` y el `docs/ROADMAP/` del hito antes de
escribir lógica nueva.

## El gate (corrélo, reportá la salida real)
```
uv run ruff check . && uv run ruff format --check . && uv run mypy src && uv run pytest
```
## Testing: iterá con el subconjunto, dejá el suite completo para el cierre
El suite completo (`uv run pytest`) tarda **~4-8 min en esta máquina** — NO lo uses como bucle de
feedback. (Lección del epic #167: correr el suite entero para triagear un fallo de UN archivo fue
**~la mitad** del tiempo perdido de los coders.)

- **En el loop:** corré SOLO los tests pertinentes a lo que tocás —
`uv run pytest tests/unit/test_X.py::TestY --tb=short` (7-60 s). Si un test falla, re-corré **ese
node id**, no el suite entero con flags distintos.
- **Antes de chequear formato/lint:** auto-formateá primero —
`uv run ruff format . && uv run ruff check --fix .` — y recién después `ruff check`/`format --check`.
Evita el gate/CI rojo **solo por formato**.
- **Cierre (una sola vez):** `uv run ruff check . && uv run ruff format --check . && uv run mypy src`
+ `uv run pytest` acotado a los archivos/áreas que tocaste. El **suite completo lo corren el
`verifier` y el CI** — no necesitás repetirlo en loop; reportá qué subconjunto corriste.
- **Timeout:** poné `timeout` ≥ 600000 ms en cualquier corrida larga de pytest (el default de 2 min
mata el suite completo).

Markers: `unit` (default, sin red), `integration` (DuckDB/red, en el gate), `network` (API real
de OpenAlex, **fuera** del gate — `-m "not network"`). TDD selectivo: test antes del código en
el núcleo; no testees wrappers finos ni plumbing de Click.
Expand Down
9 changes: 6 additions & 3 deletions .claude/agents/verifier.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ Sos el **verificador** de bib2graph. Revisás el trabajo del `coder` con ojo adv
tenés Write/Edit a propósito:** tu única salida es un veredicto honesto y hallazgos accionables.
Si algo está mal, lo marcás — no lo arreglás (arreglar destruiría tu independencia).

## El gate (corrélo, pegá la salida real)
## El gate (corrélo COMPLETO, pegá la salida real)
```
uv run ruff check . && uv run ruff format --check . && uv run mypy src && uv run pytest
```
Markers: `unit` (sin red), `integration` (DuckDB/red, en el gate), `network` (API real, **fuera**
del gate — no lo exijas). `git diff`/`git status` para ver el cambio.
**Vos sos el dueño del gate completo.** El `coder` itera con **subconjuntos** de tests (el suite
entero tarda ~6 min), así que tu corrida del **suite completo** es la red de seguridad real — corrélo
entero siempre, con `timeout` ≥ 600000 ms. Si tarda más que el límite, corré por lotes pero **cubrí
todo** y reportá honesto qué corriste. Markers: `unit` (sin red), `integration` (DuckDB/red, en el
gate), `network` (API real, **fuera** del gate — no lo exijas). `git diff`/`git status` para ver el cambio.

## Qué revisás (default a la sospecha)
1. **Correctitud:** ¿hace lo que la tarea pedía? ¿bugs, casos borde, regresiones? Buscá por qué
Expand Down
71 changes: 71 additions & 0 deletions .claude/commands/retro-ciclo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
description: >-
Retrospectiva metacognitiva de fin de ciclo — mide dónde se fue el tiempo (examina
los transcripts de los subagentes), reflexiona sobre la estrategia y APLICA mejoras al
proceso (.claude/agents/, AGENTS.md, hooks). Usala al cerrar un epic, un feature-cycle
grande, un release o una sesión con mucho fan-out. Cierra el lazo de aprendizaje.
argument-hint: "[qué ciclo cerrás: epic #N / release / sesión]"
---

# /retro-ciclo — retrospectiva del proceso de los agentes

Sos el **orquestador/tech-lead**. Acaba de cerrarse un ciclo de trabajo
($ARGUMENTS). Corré la retrospectiva **del proceso de los agentes** (no del producto:
eso es `/cosechar-sesion`) para responder con DATOS: *¿qué nos tardó más? ¿la forma de
trabajar fue la correcta? ¿en qué falla hoy y cómo lo mejoramos?* — y dejar el proceso
mejor que como lo encontraste.

## Procedimiento

1. **Medí — datos duros, no impresiones.** Los transcripts de los subagentes de esta
sesión están como JSONL en el task dir (`…/tasks/<agentId>.output`). **NO los leas
enteros** (overflow). Despachá un subagente `general-purpose` que los procese con
Bash/python línea por línea y devuelva **métricas, no dumps**:
- Wall-clock por agente (`duration_ms` de las notificaciones) y por rol
(coder/verifier/architect).
- Para los coders más lentos: #Bash/#Edit/#Read; **cuántas veces corrió el suite
completo de pytest vs subconjuntos**; ruff/mypy/uv sync; y **qué fracción del tiempo
fue esperando tests** (gaps tras `pytest`).
- Reintentos, loops editar→test→fallar, errores de formato/CRLF/encoding, timeouts,
conflictos de merge, y **trabajo perdido/rehecho** (p.ej. agentes que escribieron en
el worktree equivocado).
- **Avisá si faltan transcripts** (vacíos / no capturados): punto ciego de auditoría.

2. **Reflexioná — honesto, incluí tus propios errores de orquestación.**
- ¿Cuál fue el cuello de botella dominante? Cuantificalo.
- ¿La estrategia fue la correcta? ¿hubo cambio (p.ej. secuencial→paralelo) y valió la
pena? ¿qué fricción introdujo?
- Separá **desperdicio** de **inversión valiosa** (el rework que nace de un verifier que
cazó un bug real NO es desperdicio).
- Clasificá las lecciones: (a) generales, (b) específicas del repo (suite lento,
archivos calientes como `build.py`/`cli/__init__.py`), (c) errores puntuales de la sesión.

3. **Traé el veredicto al PO y esperá su OK.** Top 3 cuellos de botella con evidencia +
3-5 mejoras accionables. No cambies el proceso sin confirmar el rumbo.

4. **Aplicá las mejoras DONDE VIVEN** (una retro que no cambia nada es un informe, no una
mejora):
- **Comportamiento de un rol** (cómo testea el coder, qué corre el verifier) →
`.claude/agents/<rol>.md`.
- **Convención de orquestación** (paralelizar con prudencia, worktrees, batchear
decisiones) → `AGENTS.md` §"Ejecución concurrente y testing".
- **Mapa/fases del flujo** → la skill `flujo`.
- **Guardarraíl** que conviene volver imposible de violar → `.claude/hooks/`.
- Va por **PR a `dev`** (`chore(proceso): …`), porque `.claude/agents/`,
`.claude/commands/` y `AGENTS.md` están versionados.

5. **Cerrá con seguimientos.** Lo que no se baka ahora → issue (no nota suelta). Si una
lección amerita decisión de fondo → ADR vía `/graduar-adr`.

## No-negociables
- **Datos antes de opinar.** Cuantificá el cuello de botella.
- **Honestidad sobre los errores de orquestación** — la fuente más rica de mejora.
- **La retro debe cambiar algo** (bakear ≥1 lección o abrir seguimiento), o no terminó.
- No leas transcripts enteros en tu contexto; delegá la medición.

## Lecciones ya bakeadas (extender, no re-litigar)
- **Epic 0.10.0 / #167:** el suite completo de pytest (~6 min) usado como bucle de
feedback fue ~50% del tiempo de los coders → testing por capas (coder con subconjunto;
verifier+CI con el suite) en `.claude/agents/coder.md` y `verifier.md`. Paralelizar solo
archivos disjuntos; los agentes escriben en el worktree de la sesión, no en la ruta del
prompt → `AGENTS.md` §"Ejecución concurrente y testing".
24 changes: 0 additions & 24 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,27 +51,3 @@ jobs:
run: uv sync --all-extras --dev
- name: Pytest
run: uv run pytest -q

frontend:
name: frontend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Setup Node 20
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Enable corepack (pnpm pinneado en package.json)
run: corepack enable
- name: Install dependencies
working-directory: frontend
run: pnpm install --frozen-lockfile
- name: Lint (tsc --noEmit)
working-directory: frontend
run: pnpm lint
- name: Test (vitest)
working-directory: frontend
run: pnpm test:run
- name: Build
working-directory: frontend
run: pnpm build
36 changes: 16 additions & 20 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ name: publish-pypi
# - Workflow name: publish-pypi.yml
# - Environment name: pypi
#
# Mismo empaquetado que publish-testpypi.yml: se buildea el frontend ANTES del wheel y se usa
# `uv build --wheel` (no `uv build` a secas, que arma el wheel desde el sdist y pierde el frontend
# gitignored vía force-include). La única diferencia con TestPyPI es el índice destino (productivo,
# default de la action) y el environment (`pypi`).
# El paquete es Python puro (no hay frontend que buildear). `uv build` arma sdist + wheel.
# La única diferencia con TestPyPI es el índice destino (productivo, default de la action)
# y el environment (`pypi`).

on:
# Reusable: lo invoca release-please.yml (job `publish`) cuando corta un Release.
Expand All @@ -40,22 +39,19 @@ jobs:
uses: astral-sh/setup-uv@v6
with:
python-version: "3.12"
- name: Setup Node 20
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Enable corepack (pnpm pinneado en package.json)
run: corepack enable
- name: Build frontend (llena src/bib2graph/gui/static/ antes del wheel)
working-directory: frontend
run: |
pnpm install --frozen-lockfile
pnpm build
- name: Build wheel (directo del working tree, con el frontend ya buildeado)
# NO `uv build` a secas: eso arma sdist y el wheel DESDE el sdist, que
# excluye el frontend gitignored (gui/static) → force-include falla.
# `--wheel` construye el wheel directo del árbol (con el pnpm build de arriba).
run: uv build --wheel
- name: Build (paquete Python puro; sin frontend)
run: uv build
- name: Publish to PyPI (trusted publishing)
# Sin repository-url → la action publica a PyPI productivo (https://upload.pypi.org/legacy/).
uses: pypa/gh-action-pypi-publish@release/v1
with:
# attestations OFF: cuando este workflow se invoca como REUSABLE desde
# release-please.yml, el certificado de la attestation (PEP 740) registra el
# workflow top-level (release-please.yml), no este archivo. El Trusted Publisher
# de PyPI espera publish-pypi.yml → PyPI rechaza el upload con 400 ("Build Config
# URI does not match expected Trusted Publisher"). PyPA no soporta reusable
# workflows con Trusted Publishing. El OIDC del token sí matchea (job_workflow_ref
# = publish-pypi.yml), así que deshabilitar la attestation desbloquea el publish
# sin perder el trusted publishing. El disparo MANUAL (workflow_dispatch) no sufre
# esto (corre directo, no reusable), pero mantenemos el flag por consistencia.
attestations: false
18 changes: 2 additions & 16 deletions .github/workflows/publish-testpypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,8 @@ jobs:
uses: astral-sh/setup-uv@v6
with:
python-version: "3.12"
- name: Setup Node 20
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Enable corepack (pnpm pinneado en package.json)
run: corepack enable
- name: Build frontend (llena src/bib2graph/gui/static/ antes del wheel)
working-directory: frontend
run: |
pnpm install --frozen-lockfile
pnpm build
- name: Build wheel (directo del working tree, con el frontend ya buildeado)
# NO `uv build` a secas: eso arma sdist y el wheel DESDE el sdist, que
# excluye el frontend gitignored (gui/static) → force-include falla.
# `--wheel` construye el wheel directo del árbol (con el pnpm build de arriba).
run: uv build --wheel
- name: Build (paquete Python puro; sin frontend)
run: uv build
- name: Publish to TestPyPI (trusted publishing)
uses: pypa/gh-action-pypi-publish@release/v1
with:
Expand Down
14 changes: 0 additions & 14 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ snapshots/*.parquet
*.duckdb.*.bak
prueba/
prueba_e2e/
app/
redes/
valoraciones_*

Expand All @@ -61,19 +60,6 @@ valoraciones_*
# siquiera dentro de un workspace de ejemplo (ADR 0030 §Convención lo prohíbe).
examples/**/*.duckdb

# Frontend (app/) — prototipo local de la GUI (MVP), ver app/ARCHITECTURE.md
app/node_modules/
app/dist/
app/.vite/

# Frontend (frontend/) — SPA G4, build output no se commitea (va al wheel en G5)
frontend/node_modules/
frontend/dist/
# Build output del frontend: se ignora el contenido pero se conserva un .gitkeep
# para que el directorio EXISTA siempre — el force-include de hatchling (pyproject)
# rompe el editable install (uv sync en lint/test) si el dir no existe.
src/bib2graph/gui/static/*
!src/bib2graph/gui/static/.gitkeep

# Logs
logs
Expand Down
Loading
Loading