feat(ADM-018): completed feature

This commit is contained in:
chattie
2026-08-17 22:23:10 +02:00
parent cf1c69fc8b
commit d595b4871f
871 changed files with 47411 additions and 281 deletions

View File

@@ -24,6 +24,7 @@ required=(
"harness/contracts/handoff.md"
"harness/contracts/evidence.schema.json"
"harness/model-routing.yml"
"docs/context-handoff.md"
"spec/product.md"
"spec/tech.md"
"spec/acceptance.md"
@@ -36,6 +37,8 @@ required=(
"scripts/new_ticket.py"
"scripts/pi_orquestra.sh"
"scripts/run_stage.py"
"scripts/commit_feature.sh"
"scripts/close_feature.py"
"platforms/pi/README.md"
"platforms/pi/extensions/orquestra-status/index.ts"
"platforms/pi/extensions/orquestra-web-fetch.ts"
@@ -60,6 +63,16 @@ for d in "${required_dirs[@]}"; do
fi
done
# Check for prohibited directories
prohibited_dirs=("specs" "apps" "frontend" "src" "lib")
for d in "${prohibited_dirs[@]}"; do
if [ -d "$d" ]; then
fail "Directorio prohibido encontrado: $d/ (usar project/ para código)"
EXIT_CODE=1
fi
done
ok "Sin directorios prohibidos (specs/, apps/, frontend/, src/, lib/)"
root_product_files=$(find . -mindepth 1 -maxdepth 1 -type f \( \
-name '*.py' -o -name '*.js' -o -name '*.ts' -o -name '*.go' -o -name '*.rs' -o \
-name '*.java' -o -name '*.php' -o -name '*.rb' \
@@ -137,14 +150,39 @@ if len(in_progress) > 1:
print(f"[FAIL] Hay {len(in_progress)} features in_progress (máximo 1)")
sys.exit(1)
# Required fields for feature schema
required_fields = ['id', 'status']
# Valid gate names
valid_gate_names = {'reviewer', 'security', 'qa', 'close', 'leader'}
for f in features:
fid = str(f.get('id', '')).strip()
status = f.get('status')
# Check required fields
for field in required_fields:
if field not in f:
print(f"[FAIL] Feature {fid} missing required field: {field}")
sys.exit(1)
if status not in valid:
print(f"[FAIL] Estado inválido en feature {fid}: {status}")
sys.exit(1)
# Validate gate nomenclature
gates = f.get('gates', {})
if 'review' in gates:
print(f"[FAIL] Feature {fid} uses deprecated gate name 'review' (should be 'reviewer')")
sys.exit(1)
# Check for invalid gate names
for gate_name in gates.keys():
if gate_name not in valid_gate_names:
print(f"[FAIL] Feature {fid} has invalid gate name: {gate_name}")
sys.exit(1)
if status == 'done':
# Check artifacts exist
d = root / 'work' / 'artifacts' / fid
req = ['reviewer.json', 'security.json', 'qa.json', 'leader-close.json']
missing = [name for name in req if not (d / name).is_file()]
@@ -152,6 +190,11 @@ for f in features:
print(f"[FAIL] Feature {fid} done sin artefactos: {', '.join(missing)}")
sys.exit(1)
# Check gates in backlog match artifacts
if not gates.get('reviewer') or not gates.get('security') or not gates.get('qa'):
print(f"[FAIL] Feature {fid} done sin gates aprobados en backlog")
sys.exit(1)
expected = {
'reviewer.json': 'reviewer',
'security.json': 'security',
@@ -188,6 +231,24 @@ if not isinstance(runtime.get('timeline'), list):
print('[FAIL] work/runtime-status.json timeline debe ser una lista')
sys.exit(1)
# Check runtime consistency with backlog
runtime_feature_id = runtime.get('feature_id')
if runtime_feature_id:
feature_in_backlog = None
for f in features:
if f.get('id') == runtime_feature_id:
feature_in_backlog = f
break
if feature_in_backlog:
runtime_state = runtime.get('state')
backlog_status = feature_in_backlog.get('status')
# If feature is pending in backlog but running/done in runtime, that's inconsistent
if backlog_status == 'pending' and runtime_state in ['running', 'done']:
print(f"[FAIL] Inconsistencia: {runtime_feature_id} está pending en backlog pero {runtime_state} en runtime-status")
sys.exit(1)
print(f"[OK] backlog válido ({len(features)} features)")
print('[OK] runtime-status válido')
PY