agentic-dev-core · doctrina de contexto
.context/PBI/ espeja las épicas, historias y bugs de Jira en markdown local.
Durante mucho tiempo ese espejo se commiteaba, y dos sesiones que re-sincronizaban en
momentos distintos producían commits en conflicto del mismo texto generado. El modelo
nuevo lo dice sin rodeos: Jira es la fuente de verdad, el disco es un caché.
Este deck explica los tres tiers, la escalera de .gitignore que los protege,
y las defensas que evitan que el caché mienta.
Un espejo de Jira commiteado parece inofensivo hasta que dos sesiones trabajan a la vez. Cada una re-sincroniza en su momento, cada una commitea su versión del mismo archivo regenerado, y el merge de 3 vías sobre una reescritura completa no significa nada: git no puede fusionar dos fotos de la misma base de datos tomadas con minutos de diferencia. Jira ya ES la copia versionada, compartida y en la nube — commitearla duplica la base de datos dentro del repo y no compra nada.
.context/PBI/, un host desactualizado corrompe el caché con contenido de
otro sitio reportando éxito. Con el caché commiteado, esa corrupción entraba a
git en silencio. Por eso el host vive solo en
.agents/project.yaml → issue_tracker.atlassian_url y el
resolver avisa si una copia de entorno discrepa.
Cada path bajo .context/PBI/ es exactamente uno de tres
tiers. Antes de crear cualquier archivo ahí, se decide el tier — no hay archivos "más o
menos versionados".
| Tier | Fuente de verdad | ¿En git? | Se recupera con |
|---|---|---|---|
| [SYNC] | Jira | No (gitignorado) | bun run context:hydrate |
| [COMMIT] | Este repo (README.md + templates/) |
Sí | git checkout |
| [LOCAL] | Nada durable | No | No se recupera — desechable por diseño |
.session/sprint-development/<KEY>/progress.md — el contrato de
resume lee eso, nunca la copia del PBI. ¿Ninguna de las dos? Es
[LOCAL] (context.md, progress.md,
evidence/): vive solo en esta máquina y perderlo tiene que costar cero.
Nada downstream puede depender de que un [LOCAL] exista.
[SYNC] están prohibidos de escribir a mano: el sync
los sobreescribe en cada corrida y ningún archivo está protegido. El flujo es siempre
autorar → push al campo de Jira → sincronizar → leer la copia materializada.
.gitignore
El árbol entero se excluye y las dos excepciones commiteadas se re-incluyen justo
después. La forma exacta importa: git no puede re-incluir un archivo
cuyo directorio padre está excluido, así que colapsar la escalera a una sola línea
.context/PBI/ descarta las excepciones en silencio.
# ===== PBI: caché respaldado por Jira (Jira es la fuente de verdad) ===== .context/PBI/* ← se excluye el CONTENIDO (/*), no el directorio !.context/PBI/README.md ← re-incluido: reglas de tiers [COMMIT] !.context/PBI/templates/ ← re-incluido: esqueletos [COMMIT] .context/PBI/ ← MAL: excluye el directorio y las negaciones mueren
Los context.md / progress.md / evidence/ de cada
historia quedan deliberadamente sin negar: son [LOCAL] y se quedan en el
disco de quien los hizo.
git check-ignore -v:
sobre .context/PBI/README.md no debe reportar ignore, y
sobre un stories/.../story.md sí debe. Dos comandos, cero
fe.
Un clon fresco trae un .context/PBI/ casi vacío — solo el README y
templates/. Ese es el estado intencional, no un checkout roto.
El caché completo se reconstruye con un comando:
bun run context:hydrate # = jira:sync-issues pull --include-comments
ATLASSIAN_EMAIL y ATLASSIAN_API_TOKEN en
.env; el host sale de .agents/project.yaml →
issue_tracker.atlassian_url.
bun run jira:sync-issues get PROJ-42 --include-comments trae UN issue con
todos sus custom fields (acli view devuelve null para
customfield_*).
Los planes de implementación viven en Jira como custom fields — así el bucle de desarrollo sobrevive resets de sesión y pérdidas de contexto local. Hay exactamente dos altitudes:
| Campo | Vive en | Altitud | Se materializa como |
|---|---|---|---|
feature_implementation_plan |
el Epic | macro — plan técnico de la feature entera; lo escribe el precheck de épica de
/sprint-development |
epics/EPIC-PROJ-20-.../feature-implementation-plan.md |
spec_implementation_plan |
la Story | micro — la tajada por historia del plan padre | stories/STORY-PROJ-42-.../implementation-plan.md |
En la etapa de planning, nunca directo a un archivo [SYNC].
Epic o Story según la altitud. El plan queda donde sobrevive.
jira:sync-issuesMaterializa el .md local desde el campo.
Todo lo que sigue lee el caché, jamás un borrador local.
## <label>, según
.agents/jira-required.yaml → fallback:) y el sync emite un
stub apuntador para ese .md. Nunca se bloquea por un campo ausente.
El mismo proyecto de Jira lo comparten el lado dev y el boilerplate QA hermano. El sync trae cuatro defensas para que los artefactos de un lado no contaminen el árbol del otro:
epics/
Un Epic con el label QA-Artifact es un bucket de artefactos QA, no un
módulo del producto: se archiva bajo qa-artifacts/. Tres señales en
orden de confianza: el label (autoritativo), las keys cacheadas en
qa.qa_epics.*.key, y el prefijo de nombre QA como
último recurso.
La escalera QA pone ATP: / ATR: / ATS: a
altitud de Story; FTP: (feature), STP: /
STR: (sprint) y MTP: (master) viven más arriba. Un link a
un artefacto de altitud mayor se nombra en un INFO y jamás se
materializa dentro de la carpeta de la Story.
Qué work types barre pull lo declara
.agents/jira-required.yaml (sync: default). El default de
fábrica resuelve a Bug solamente — Defect, Improvement o Tech Story
son tipos custom y se piden con --types. Los tipos presentes en Jira que
la corrida no tocará se nombran, para que una carpeta vacía se lea como configuración
y no como bug.
_orphans/ es una lista de trabajo
Una Story sin Epic padre cae en epics/_orphans/ en vez de fallar. Un
Test cuya única casa es membership interna de Xray (GraphQL-only, este repo no lleva
cliente Xray) queda huérfano a la vista: el fix es re-linkearlo en Jira. Los Defects
sin padre coverable se reportan con sus keys para re-linkear.
Un proyecto scaffoldeado antes de esta regla todavía trackea archivos
[SYNC] en git. Al correr bun run up, un hook post-apply lista lo
que git trackea bajo .context/PBI/, resta el allowlist commiteado
(README.md + templates/**) y — si sobra algo — persiste un
prompt de migración para el agente de IA del consumidor. El hook jamás
toca el índice de git: destrackear es trabajo destructivo-adyacente que el agente hace con
un punto de recuperación puesto.
ATLASSIAN_*
en .env).
bun run jira:sync-issues pull
El sync de .gitignore de bun run up agrupa una corrida de
líneas con prefijo común que contiene una negación como
un grupo todo-o-nada: una escalera de re-include aplicada a medias
es peor que no aplicarla. El picker interactivo la ofrece como una sola decisión.
El updater filtra los paths solo-del-boilerplate antes de ofrecer nada:
.github/workflows/pages.yml y ci.yml, los mapas
business-*-map.md generados, y los catálogos
jira-fields.json / jira-workflows.json por instancia. Un
consumidor regenera los suyos; el update solo toca framework.