Recorrido manual: el bucle de gobernanza a mano (Bajo el capó)
Modo avanzado. No necesitas este laboratorio para usar Rapid OS: escribe en una terminal, uno a uno, los comandos de uso diario (
rapid start,rapid next,rapid check,rapid task,rapid approve,rapid finish) que el agente ejecuta por ti con los shortcuts. Es para integradores, CI y auditoría. Si estás empezando, ve a los laboratorios, empezando por Feature (/rapid-feature).
Aprende a ejecutar el bucle de gobernanza completo de RAPID OS sobre un proyecto Python real, viendo qué registra cada paso y por qué un veredicto solo llega a pass con tests reales y una aprobación humana real.
1. Overview
- Nombre: Task Tracker CLI Governance.
- Problema: Un proyecto Python sin gobernanza arriesga cambios no validados introducidos por asistentes de IA. Se requiere implementar una nueva funcionalidad de prioridad de tareas bajo un contrato verificable.
- Objetivo: Recorrer todo el ciclo de gobernanza, desde
rapid inithasta el informe de evaluación y la validación final de integridad, solo con los comandos de uso diario. - Nivel de dificultad: Avanzado.
- Conocimientos previos: Uso básico de terminal, git y comandos de Python.
- Dependencias: Python 3.10+ (exclusivamente biblioteca estándar) y git.
- Archivos de referencia:
examples/first-governed-project/.
2. Learning Outcomes
Al completar este laboratorio, sabrás cómo:
- Inicializar RAPID OS en un repositorio git existente.
- Abrir un run gobernado desde un archivo de spec (
rapid start feature --spec-file), que además registra la baseline. - Pedir a Rapid OS el siguiente paso determinista (
rapid next). - Trabajar en una tarea y cerrarla con sus tests (
rapid task start,rapid task done). - Satisfacer los gates de máquina con checks que ejecuta el propio Rapid OS (
rapid check). - Aprobar el gate humano desde tu propia terminal (
rapid approve). - Terminar el run y obtener su informe de evaluación (
rapid finish,rapid eval run --require-pass). - Validar la integridad holística del proyecto (
rapid validate). - Distinguir los comandos de plomería (
rapid evidence add,rapid run gate), que nunca satisfacen un gate de tests ni uno humano.
3. Initial State
La aplicación inicial es un gestor de tareas en memoria:
task-tracker/
├── app.py
└── tests/
├── __init__.py
└── test_app.py
Estado inicial de app.py:
# app.py
"""Minimal Task Tracker application."""
class TaskTracker:
def __init__(self):
self.tasks: list[dict[str, object]] = []
def add_task(self, title: str) -> dict[str, object]:
if not title or not title.strip():
raise ValueError("Task title cannot be empty.")
task = {
"id": len(self.tasks) + 1,
"title": title.strip(),
"status": "pending",
}
self.tasks.append(task)
return task
def list_tasks(self) -> list[dict[str, object]]:
return list(self.tasks)
Estado inicial de tests/test_app.py:
# tests/test_app.py
import unittest
from app import TaskTracker
class TestTaskTracker(unittest.TestCase):
def setUp(self):
self.tracker = TaskTracker()
def test_add_and_list_tasks(self):
task = self.tracker.add_task("Initial task")
self.assertEqual(task["id"], 1)
self.assertEqual(task["title"], "Initial task")
self.assertEqual(task["status"], "pending")
self.assertEqual(len(self.tracker.list_tasks()), 1)
def test_reject_empty_task(self):
with self.assertRaises(ValueError):
self.tracker.add_task("")
if __name__ == "__main__":
unittest.main()
Inicialización del paquete de pruebas tests/__init__.py:
# tests/__init__.py
"""Test package initialization."""
En este estado inicial, TaskTracker.add_task(title) solo acepta el título de la tarea y le asigna el estado pending.
4. Engineering Requirements
- Nueva funcionalidad: Permitir especificar la prioridad de la tarea (
low,medium,high), conmediumpor defecto. - Validación: Rechazar prioridades desconocidas con
ValueError. - Filtrado:
list_tasks(priority=None)debe permitir filtrar por prioridad cuando se indique una. - Preservación: No romper las pruebas unitarias existentes.
5. Guided Procedure
Paso 1: Poner el starter bajo git
Rapid OS observa los cambios de un run con git, así que el proyecto parte de un commit:
git init
git add .
git commit -m "Starter task tracker"
Paso 2: Inicializar RAPID OS
En la raíz del proyecto, inicializa Rapid OS sin preguntas (--yes) con un stack Python:
rapid init --stack python-ai --yes
Esto crea la estructura .rapid-os/ con sus estándares y configuración base. Detecta la carpeta tests/ y registra python -m unittest discover como test_command del proyecto: el comando en el que Rapid OS confía para ejecutar los tests.
Paso 3: Escribir la spec
La spec dice qué debe lograr el run y qué tareas tiene. Guárdala como spec.json:
{
"title": "Task priority",
"business_objective": "Tasks carry a priority so the most urgent work can be listed first.",
"acceptance_criteria": [
"add_task accepts the priorities low, medium and high, and medium by default",
"add_task rejects an unknown priority with ValueError",
"list_tasks(priority) returns only the tasks of that priority"
],
"implementation_tasks": ["T001: Implementar soporte de prioridades en TaskTracker"]
}
Paso 4: Iniciar el run
rapid start feature --spec-file spec.json
rapid start guarda la spec (id task-priority), resuelve la política de ejecución y crea el run task-priority-r1-run-001 con su ExecutionContract inmutable. Para una spec feature sobre un stack de backend, el contrato exige estos gates:
gate.baseline(fasepre_execution): la suite de tests pasa antes de cambiar nada.rapid startejecuta él mismotest_commandy registra el resultado como evidenciatest_resultproducida porrapid:check; con la baseline satisfecha, activa el run.gate.tests(fasepost_execution): la suite de tests pasa sobre el código final.gate.architecture(fasepost_execution): este proyecto se inicializó con un stack de backend (python-ai), así que parte como monolito modular y la regla se verifica conrapid arch check.gate.final-verification(fasepost_execution): una persona aprueba el resultado, en su propia terminal.
Paso 5: Pedir el siguiente paso
rapid next
Rapid OS responde con la siguiente acción determinista y su comando exacto: implement_task -> rapid task start T001. Siempre que dudes de qué sigue, rapid next te lo dice.
6. External Execution
Nota de límite de responsabilidad: RAPID OS no edita el código. La implementación la hace el desarrollador o su coding harness externo (Claude Code, Cursor, Codex, Antigravity, etc.).
Paso 1: Empezar la tarea
rapid task start T001
Paso 2: Implementar el código y sus tests
Modifica app.py y tests/test_app.py para cumplir los requisitos:
# app.py
"""Enhanced Task Tracker application with priority support."""
class TaskTracker:
VALID_PRIORITIES = ("low", "medium", "high")
def __init__(self):
self.tasks: list[dict[str, object]] = []
def add_task(self, title: str, priority: str = "medium") -> dict[str, object]:
if not title or not title.strip():
raise ValueError("Task title cannot be empty.")
priority_normalized = priority.lower().strip()
if priority_normalized not in self.VALID_PRIORITIES:
raise ValueError(f"Invalid priority '{priority}': must be one of {self.VALID_PRIORITIES}.")
task = {
"id": len(self.tasks) + 1,
"title": title.strip(),
"priority": priority_normalized,
"status": "pending",
}
self.tasks.append(task)
return task
def list_tasks(self, priority: str | None = None) -> list[dict[str, object]]:
if priority is None:
return list(self.tasks)
p = priority.lower().strip()
return [t for t in self.tasks if t["priority"] == p]
Actualiza la suite en tests/test_app.py:
# tests/test_app.py
import unittest
from app import TaskTracker
class TestTaskTracker(unittest.TestCase):
def setUp(self):
self.tracker = TaskTracker()
def test_add_and_list_tasks_default_priority(self):
task = self.tracker.add_task("Initial task")
self.assertEqual(task["id"], 1)
self.assertEqual(task["title"], "Initial task")
self.assertEqual(task["priority"], "medium")
self.assertEqual(task["status"], "pending")
self.assertEqual(len(self.tracker.list_tasks()), 1)
def test_add_task_with_custom_priority(self):
t1 = self.tracker.add_task("Urgent bug", priority="high")
t2 = self.tracker.add_task("Clean backlog", priority="low")
self.assertEqual(t1["priority"], "high")
self.assertEqual(t2["priority"], "low")
high_tasks = self.tracker.list_tasks(priority="high")
self.assertEqual(len(high_tasks), 1)
self.assertEqual(high_tasks[0]["title"], "Urgent bug")
def test_reject_invalid_priority(self):
with self.assertRaises(ValueError):
self.tracker.add_task("Invalid", priority="critical")
def test_reject_empty_task(self):
with self.assertRaises(ValueError):
self.tracker.add_task("")
if __name__ == "__main__":
unittest.main()
Paso 3: Cerrar la tarea con sus tests
rapid task done T001
rapid task done ejecuta test_command antes de cerrar la tarea. Si un test falla, la tarea sigue abierta y el comando sale con el fallo.
7. Evidence Collection
Toda la evidencia de este recorrido la escribe el propio Rapid OS mientras ejecuta algo. Nunca escribes evidencia a mano.
1. Verificar los gates de máquina
Pide el siguiente paso:
rapid next
Responde verify -> rapid check --gate gate.tests -- python -m unittest discover. Ejecuta el comando que da:
rapid check --gate gate.tests -- python -m unittest discover
rapid check ejecuta el comando sin shell, guarda su salida como log en .rapid-os/scratch/checks/, lee el resumen de tests (Ran 4 tests ... OK) y registra evidencia test_result producida por rapid:check con los conteos, counted: true y la huella (tree) del árbol de trabajo que verificó.
Después, el gate de arquitectura. rapid next lo propone con --new-only (solo fallan las violaciones que añade el run); este proyecto aún no tiene módulos, así que el checker sin opciones también pasa:
rapid next
rapid check --gate gate.architecture -- rapid arch check
2. Qué no cuenta como ejecución de tests
Un gate de tests (gate.tests, gate.baseline) solo lo satisface un check que ejecutó Rapid OS cuya salida tenía un resumen de tests que pudo contar (pytest, unittest, vitest, jest, cargo test, go test -v) o cuyo comando es exactamente test_command, con al menos un test ejecutado y el árbol de trabajo registrado. Por eso:
rapid check --kind test -- python -c "print('hello')", ligado agate.tests, pasa como comando, pero se registra comocommand_resultyrapid nextsigue pidiendo el comando de test real (RAPID1432).- Si el código cambia después del último check,
rapid next,rapid approveyrapid finishpiden un check nuevo y nombran los archivos (RAPID1423).
3. Aprobar el gate humano
rapid next responde ahora await_human_approval -> rapid approve gate.final-verification. Revisa el diff y ejecuta, en tu propia terminal (no desde dentro de un agente):
rapid approve gate.final-verification
Rapid OS te pide escribir la frase aprobar gate.final-verification. Registra una evidencia review escrita por rapid approve, con tu nombre y la huella del árbol de trabajo que aprobaste. Un agente no puede hacerlo: dentro de una sesión de agente, bajo un proceso de agente o sin TTY se rechaza (RAPID1310).
8. Evaluation
Termina el run:
rapid finish
rapid finish registra los archivos cambiados (file_change, producido por rapid:finish), reconoce los gates de máquina cuya evidencia los satisface, comprueba que el código sigue siendo el que verificaron los tests y el que aprobaste (si no, se niega con RAPID1423 o RAPID1433 y nombra los archivos) y escribe el informe de evaluación con el veredicto.
Vuelve a leer el informe y exige el veredicto exitoso (--require-pass sale con error si el veredicto no es pass):
rapid eval run --run task-priority-r1-run-001 --require-pass
El evaluador (ruleset 3) revisa el ciclo de vida del run, las tareas, los gates requeridos (gate.baseline, gate.tests, gate.architecture, gate.final-verification) y las capacidades observadas, y emite el veredicto:
{
"verdict": "pass",
"run_id": "task-priority-r1-run-001"
}
9. Validation
Valida la integridad criptográfica de todo el repositorio:
rapid validate
10. Referencia: los comandos de plomería
Los comandos de uso diario se apoyan en comandos de más bajo nivel que siguen disponibles para integradores y CI: rapid scan, rapid spec, rapid context, rapid policy show, rapid run create, rapid run task, rapid run gate, rapid evidence add y rapid eval run. Dos de ellos escriben en el registro y tienen límites que importan:
rapid evidence addno satisface gates de tests ni humanos. Registra evidencia producida fuera de Rapid OS (harness:<id>,ci:<nombre>,external:<nombre>). Los productoresrapid:*y la evidenciareviewde produceruserestán reservados a los comandos que los observan (rapid check,rapid start,rapid finish,rapid attach,rapid approve):evidence addlos rechaza conRAPID1430. Untest_resultescrito a mano nunca satisfacegate.testsnigate.baseline: el gate quedaunverified.rapid run gateno cambia gates humanos.rapid run gate <run> gate.final-verification acknowledgedse rechaza conRAPID1431; un gate humano solo se mueve conrapid approve <gate>en la terminal de la persona. Reconocer un gate de tests conrapid run gatesin un check derapid checkdeja su aserción enunverified.
Por ejemplo, los dos se rechazan:
rapid evidence add --run task-priority-r1-run-001 --input review_a_mano.json # producer "user", kind "review" -> RAPID1430
rapid run gate task-priority-r1-run-001 gate.final-verification acknowledged # gate humano -> RAPID1431
La lista completa de comandos está en la referencia de la CLI y en el bucle de gobernanza v3.
11. Troubleshooting & Common Errors
RAPID1432(gate de tests no verificable): la evidencia vinculada agate.testsogate.baselineno era una ejecución de tests de la que Rapid OS pueda responder (sin resumen de tests y sin sertest_command, cero tests ejecutados, sin árbol registrado, o escrita conrapid evidence add). Ejecuta el comando que darapid next.RAPID1423/RAPID1434(código no verificado): el código cambió después del último check de tests, o ese check no registró qué árbol verificó. Vuelve a ejecutar el check de tests.RAPID1433(el código cambió después de la aprobación): vuelve a ejecutar el check de tests y aprueba de nuevo conrapid approve <gate>.RAPID1435(otro comando de tests que el de la baseline): repite el check con el comando de la baseline; solo la persona puede aceptar la diferencia, en su terminal, conrapid finish --accept-test-command "MOTIVO".- Error
RAPID1225/RAPID1226(Evaluation Unverified / Fail): un gate requerido no está satisfecho por evidencia válida, o la evidencia asociada tieneexit_code != 0o tests fallidos.rapid nextnombra lo que falta.
12. Assessment Criteria
- Repositorio bajo git y RAPID OS inicializado.
- Run iniciado desde
spec.json, con la baseline registrada porrapid start. - Tarea
T001implementada y cerrada conrapid task done. -
gate.testsygate.architectureverificados conrapid check. -
gate.final-verificationaprobado conrapid approveen la terminal de una persona. - Run terminado con
rapid finishy veredictopassconfirmado porrapid eval run --require-pass. -
rapid validatefinaliza con código de salida 0. - Ninguna evidencia escrita a mano: sin
rapid evidence addnirapid run gate.