El cambio
El cambio del ecosistema: se planifica en el brain, se ejecuta en cada repo que la funcionalidad toca y se cierra de vuelta en el brain. El verbo al que sirven los otros tres trabajos.
multivac change new "points expire"
multivac change plan <slug> # which repos, in what order, which invariants it touches
multivac change apply <slug> # branch per repo from its default branch, edits, commits
multivac change land <slug> # MRs respecting the declared order
multivac change close <slug> # updates the brain and verifies the declared claimsCuatro campos declarados
Un cambio declara, antes de tocar nada:
Qué repos toca. Claves del registro. Un repo que aún no existe es válido:
applyen modo greenfield lo crea.Orden de aterrizaje: etapas ordenadas. Cada etapa es una lista de claves de repo; los repos de la misma etapa aterrizan en paralelo; una etapa aterriza solo después de todas las anteriores:
landing_order: - [api] # web and worker consume what api serves - [web, worker]El orden es ley para
land; declara solo el orden que sea una restricción real: una lista vacía es una única etapa en paralelo.Qué invariantes toca, bajo la regla: un invariante nunca se relaja en el código; se cambia primero en la ley, con fecha, dentro del mismo cambio.
Qué filas hace verdaderas: sus afirmaciones (claims), cada una el ID de una fila, con sus anclas. La fila enuncia la regla; la afirmación la cita y nunca la repite. Este es el contrato que
closeverifica. Redacta las anclas ahora, mientras la promesa está fresca: después del merge nadie la recuerda.
El archivo del cambio
Un cambio es un archivo en el brain: .multivac/changes/<slug>.md, que
lleva los cuatro campos declarados más el estado por repo
(planned / branched / committed / mr / landed). Ese archivo es el estado que
los cinco subcomandos leen y escriben, a lo largo de días y máquinas. Al
cerrarse se archiva, nunca se borra.
Terminado cuando sus anclas resuelven
Un cambio no está terminado cuando se hace merge. Está terminado cuando sus anclas resuelven.
Como las afirmaciones se declararon desde el principio, close no pregunta si
alguien actualizó la documentación: vuelve a ejecutar verify acotado a las
afirmaciones declaradas y se rechaza a archivar hasta que:
- cada afirmación del campo 4 resuelva ok o moved en sus nuevas anclas,
- cada afirmación cite una fila que este cambio agrega, toca o retira, y esa fila enuncie su regla,
- cada repo declarado esté registrado como aterrizado,
- ninguna afirmación esté anclada solo en el archivo del cambio, que
closearchiva, y ninguna fila que el cambio agrega quede sin afirmar mientras está anclada o ya está en la ley, - existan los artefactos propios del SDD, donde se haya declarado uno.
Ese alcance es deliberado y es más estrecho de lo que parece: close evalúa
los IDs de afirmación que el cambio declaró, no las filas bajo touches ni
retires, y nunca ejecuta un verify sin acotar. Una fila modificada que nadie
listó como afirmación no se vuelve a comprobar aquí: verify la reporta en
cada commit donde los hooks están armados. Un tramo de ella bloquea solo cuando
está roto o vacuo en un modo que bloquea (por defecto absent, count y
each), o en cualquier modo bajo --strict, como lo ejecuta el CI, y los
tramos de una fila proposed o drift solo se reportan. Una línea de ancla
que no se puede interpretar, o que nombra una clave de repo que la
configuración no declara, se rechaza en cualquier fila. Declara como
afirmaciones las filas que modificas si quieres que close sea quien
responda.
Donde sdd_auto está activado y un SDD gobierna un repo declarado (el brain
mismo, cuando se declara como uno), el código también llega a través del
cambio. En el checkout propio del brain y en los worktrees de un cambio, se
rechaza un commit o un merge de código fuera de la rama de un cambio abierto
que declare el repo, y también un merge request cuyos commits lo hagan,
cuando el pipeline ejecuta
verify --strict --range <base>..<head> --branch <name>. Un checkout
consumidor lee un brain montado que puede ir por detrás del cambio, así que
allí una rama que no es un cambio abierto solo se reporta y decide la
ejecución con --range en el CI, mientras que una rama cuyo cambio abierto no
declara el repo se rechaza en cualquier ejecución. Un cambio es la forma en que el código llega a un
repo, no una descripción escrita a su lado.
Actualizar la documentación deja de ser disciplina y se vuelve mecanismo. No se inventa nada nuevo: el cambio declara antes lo que hoy se comprueba después, cuando alguien lo recuerda.
El ritual
Cerrar un cambio es una ceremonia, y solo la mitad es mecánica. multivac ejecuta esa mitad: cada repo declarado aterrizado, cada afirmación declarada resuelve y cita una fila de la ley que enuncia su regla. La otra mitad es del equipo: quién revisa qué, a quién se avisa, qué sale antes de qué cuando la razón no es técnica. Ninguna herramienta puede inventar eso, y ninguna puede comprobarlo.
Así que el equipo lo escribe, una línea cada uno, en .multivac/ritual.md
junto a la ley, y close imprime esas líneas como una lista de verificación
una vez que la compuerta ha pasado y el cambio está archivado:
$ mvac change close points-expire
…
ritual (.multivac/ritual.md) — multivac cannot check these; walk them with the user:
- [ ] tell support before the flag flips
- [ ] the public site ships before the backendLo que close imprime antes del ritual (las afirmaciones, el archivo y el
commit por hacer) está en la referencia de comandos.
Impreso, no verificado. Nada bloquea por el ritual y nada lo comprueba;
los encabezados y los comentarios se omiten, así que un ritual vacío o ausente
no imprime nada en absoluto. init genera el archivo con una explicación y
líneas candidatas, todas comentadas, y la puerta del brain lo nombra.
Tiene su propio archivo y no una sección de la ley porque la ley se analiza:
verify lee sus anclas, plan lee sus celdas de estado; y el ritual es prosa
que la herramienta solo imprime.
Planificado: un cambio que no ha comenzado
Un roadmap es la lista de cosas que un ecosistema pretende hacer, y el brain
ya guarda esa lista. Todo archivo de cambio nace open, lo que significa que
se da por hecha una rama y se reserva un id de invariante. Así que, sin un
estado más, la única forma de anotar una intención es comprometerse a empezarla
hoy, y la alternativa a la que la gente recurre es una segunda lista en un wiki
o en un tracker, que se desvía de la primera en una semana. La lista que la
herramienta no lee se vuelve ficción.
planned se ubica antes del ciclo de vida:
planned → open → archivedEs el mismo archivo, en el mismo directorio, con el mismo esquema, más un
horizon de now, next o later. Ese es todo el modelo de orden: sin
fechas, sin estimaciones, sin ranking, sin dependencias entre elementos.
Empezar el trabajo es change new <slug> sobre un slug que ya está
planificado: el archivo se promueve, no se reemplaza, de modo que la prosa
escrita cuando la idea era joven sobrevive en el cambio que la implementa. Un
documento, una historia.
Tres propiedades hacen que el estado sea seguro de usar y no decorativo:
- No reserva nada. Un id asignado a un trabajo que quizá nunca ocurra es un
hueco en la tabla de la ley que ningún cambio posterior puede llenar. La
reserva se queda en
change new, el momento en que el trabajo realmente comienza. - No bloquea nada.
verify --strictrechaza un cambio solo cuando ya está terminado y sigue sin cerrar: cada afirmación resuelve, cada repo declarado aterrizado. Un cambio planificado no tiene ninguna de las dos cosas, así que ninguna entrada del roadmap puede retener un release, por mucho que el roadmap siga sin estar vacío. - No es una compuerta.
change newsobre un slug que nadie planificó funciona exactamente como siempre. Exigir que una funcionalidad aparezca primero en el roadmap es una intención inverificable, de la misma categoría que el ritual, y por eso el ritual se imprime y nunca se comprueba. Una compuerta que todos aprenden a saltarse a las tres de la mañana enseña a la gente a esquivar la herramienta.
Todo paso posterior (plan, apply, land, close) rechaza un cambio que no
ha comenzado y nombra change new como el paso que va primero. Donde se declara
un SDD, plan, apply y close ejecutan su compuerta antes de esa
comprobación, así que su rechazo puede deberse a un artefacto faltante;
close --abandon no ejecuta ninguna compuerta, así que un cambio planificado
siempre recibe allí el rechazo de no iniciado.
Consulta roadmap
para el comando, y Ejecutar cambios
para el flujo.
El ritual llega con candidatos
init solía escribir el ritual como un comentario vacío, y ante una página en
blanco la mayoría no escribe nada, así que el paso de cierre no imprimía nada
nunca. Ahora trae candidatos sacados de lo que declaraste, todos comentados.
Una ceremonia no adoptada no es una ceremonia. Descomenta lo que tu equipo realmente se debe y borra el resto; no se afirma nada en tu nombre, y una línea comentada nunca se imprime. Un brain nuevo sigue sin imprimir nada al cerrar, que es exactamente lo que hacía antes.
Solo se siembran cosas que ninguna comprobación podría decidir: poner algo comprobado en el ritual lo llevaría a un póster.
El ritual es de autoría propia: lo escribes una vez tú y ningún comando lo
sobrescribe. Es lo opuesto a
flow.md,
que es derivado y se reescribe completo en cada proyección.
Los subcomandos
- plan resuelve la declaración contra la realidad: qué repos declarados
están presentes, qué implica el orden, qué toca el cambio. Un repo declarado
que falta en local y tiene
urlse clona aquí: una operación explícita que lo necesita, el mismo contrato quegit submodule update. - apply crea una rama en cada repo desde su rama por defecto, resuelta en
este orden: a donde apunta
origin/HEAD, luego elinit.defaultBranchde esta máquina, luegomain, luegomaster, nunca un nombre fijo; si no existe ninguna, crea la rama desde el HEAD actual y lo dice. Un repo que no existe se clona desde suurl, o se crea con su puerta de consumidor cuando no tiene ninguna. Las ediciones y los commits son tuyos, en esas ramas. El paso apply de un adaptador SDD declarado se imprime aquí para que lo ejecutes (--no-sddomite la impresión, el init propio de la herramienta en el brain y la compuerta de este paso por una ejecución; los pasos posteriores la necesitan de nuevo). - land reporta el orden de MRs que dictan las etapas: qué está listo para
hacer push ahora, qué está bloqueado detrás de una etapa anterior. No abre
nada (multivac no tiene integración con ningún forge) y
--landed <repo>sirve para que registres un merge. - close es la compuerta de arriba. Si tiene éxito, el archivo del cambio se archiva; las filas que el cambio prometió ya están en la ley, promulgadas por el humano.
Las decisiones tomadas a mitad de un cambio se vuelven afirmaciones al cerrar: el agente propone la fila, el humano la promulga. Esta es la vía orgánica de nacimiento, la principal en régimen estable.
Greenfield
Un cambio cuyos repos aún no existen: apply los crea (git init, la puerta
del consumidor, un primer commit) para que la primera sesión del agente en
cada uno parta en una puerta que lo apunta a la ley; el brain mismo se monta
con multivac repos sync. El brain precede al código. Sin una segunda
maquinaria: apply sabe crear, no solo editar.