Gate determinista de complejidad y task-contracts (CCDD), con servidor MCP. Sin LLM en el veredicto.
Project description
ccdd-gate
Gates deterministas que mantienen honesto al código escrito por IA. Un modelo pequeño implementa; un árbitro que no se puede sobornar decide si pasó.
No es otro loop "dale al modelo grande hasta que diga que está listo". La condición de parada no es el juicio del modelo —es un veredicto determinista: complejidad ≤ budget firmado + property-tests congelados que el implementador no puede ablandar. Mismo input, mismo veredicto, corrida a corrida.
El mismo principio cubre dos pilares:
- Código (gate de complejidad/tests): verifica que la función implementada respeta el budget y pasa los property-tests congelados. 100% determinista.
- Comportamiento de agentes (pilar de evals): para la salida NO determinista de un agente (texto/JSON), un dataset congelado + checks deterministas (schema, contención, citas/groundedness anti-alucinación, PII, trayectoria) deciden PASS/FAIL sin LLM (Tier 1); un juez LLM acotado y auditado contra un golden set es Tier 2 opt-in. Ver Pilar de evals.
Construido sobre CCDD (incluido aquí como
ccdd.py, MIT). El sustrato determinista no llama a ningún LLM: el cerebro es el agente anfitrión (Claude Code, Cursor, etc.) que invoca estas herramientas.
La idea en una frase
El modelo grande planifica y audita; el modelo pequeño (local/barato) implementa; un gate determinista decide. El grande solo entra a autorar la tarea, auditar los tests y rescatar cuando el chico se atasca. La inteligencia difusa va en el LLM; el control y el veredicto van en código que no se puede engañar.
Qué hay acá
| Pieza | Qué hace | LLM |
|---|---|---|
runners/metrics_backends.py |
Capa neutral compartida (umbrales + severity + lint_results) y registro get_backend(language|extension) para backends por lenguaje |
no |
runners/metrics.py |
Backend Python: métricas de complejidad por AST (ciclomática, anidamiento, params, longitud) | no |
runners/metrics_treesitter.py |
Backend universal vía tree-sitter (TS/TSX/JS) — dep opcional; sin ella, solo Python | no |
runners/pre_complexity_runner.py |
Orquestador L3 para el contrato pre-complexity-agent |
no |
runners/pre_complexity_helpers.py |
Data-helpers para inyectar contexto de diseño y negocio | no |
runners/complexity_runner.py |
Orquestador L3 para el contrato complexity-agent |
no |
runners/complexity_gate.py |
Gate determinista; CLI o hook PostToolUse de Claude Code | no |
runners/tc_lint.py |
Linter del task-contract (anti-desvarío del autor) | no |
runners/task_gate.py |
Veredicto unificado: tc_lint + tests congelados + complejidad≤budget + anotaciones + firma implementada (gate-signature) + deps opt-in (gate-deps) + aprobación; kind:group compone hijas + test de integración |
no |
runners/deps_check.py |
unauthorized_imports: imports top-level de terceros NO permitidos (núcleo del enforcement de deps_allowed / anti-slopsquatting). AST puro |
no |
runners/sig_check.py |
signature_mismatch: la firma IMPLEMENTADA vs la del contrato (nombre + nombres de params en orden); caza el drift de firma. AST puro |
no |
runners/purity_check.py |
impure_operations: operaciones impuras en el cuerpo (print/open/eval/exec/import/input, global/nonlocal, import interno). AST puro |
no |
runners/mutdef_check.py |
mutable_defaults: params con default mutable ([]/{}/set()/list()/dict()). AST puro |
no |
runners/bareexcept_check.py |
bare_except_lines: líneas de except: desnudo (sin tipo). AST puro |
no |
runners/assert_check.py |
assert_lines: líneas de assert (desaparecen con python -O). AST puro |
no |
runners/nonecmp_check.py |
none_eq_lines: comparaciones con None por ==/!= (en vez de is/is not). AST puro |
no |
runners/coverage_check.py |
function_lines: líneas del cuerpo que la ejecución debería cubrir (primitivo, sin etapa). AST puro |
no |
runners/rules_gate.py |
Aplica los checks deterministas project-wide por glob desde un rules.yaml (idea declarativa estilo autorules, árbitro AST sin LLM) |
no |
runners/audit_composition.py |
Auditor project-wide: composición sin gatear (función importa a otra sin kind:group); distingue deuda de FORMA vs de COMPORTAMIENTO |
no |
runners/audit_orphan_targets.py |
Auditor project-wide: .py de implementación que no son target de ningún contrato (código fuera del flujo gate); exime datos puros |
no |
runners/audit_annotations.py |
Auditor project-wide: nombres en anotaciones sin importar/definir; caza bugs de portabilidad que lazy annotations (PEP 649) enmascara | no |
runners/mutation_audit.py |
Mide la fuerza del oráculo vía mutation testing determinista (mutaciones fijas → corre los tests congelados por mutante); superviviente = test débil | no |
runners/approve_tests.py |
Firma humana de los tests (tests_sha256), a prueba de manipulación |
no |
runners/orchestrator.py |
Loop stateless: pequeño implementa → tests fallan/complejidad falla → reintenta (sin memoria) → escala al grande | sí (worker) |
runners/test_audit.py |
Auditoría advisory de los tests contra el contrato | sí (advisory) |
runners/measure.py |
Harness de medición: tokens/intentos/escalados, costo vs loop grande | no |
runners/complexity_mcp.py |
Servidor MCP (stdio JSON-RPC) que expone el sustrato | no |
runners/mcp_smoke.py |
Smoke test del MCP | no |
runners/guardrails_lang.yaml |
Guardrails específicos por lenguaje | no |
runners/eval_gate.py |
Pilar de evals — Tier 1: veredicto determinista sobre output NO determinista (agentes). Dataset congelado + checks (schema, contención, citas/groundedness, PII, trayectoria) | no |
runners/eval_checks.py |
Checkers deterministas Tier 1 (una función por check; anti-alucinación de fuentes y evaluación de trayectoria) | no |
runners/approve_eval_cases.py |
Firma humana del dataset de evals (cases_sha256), a prueba de manipulación |
no |
runners/eval_judge.py |
Tier 2 (opt-in): juez LLM acotado (modelo pinneado, temp 0) — el único módulo del pilar que llama a un LLM | sí (opt-in) |
runners/judge_audit.py |
Fuerza/deriva del juez: acuerdo vs golden set humano (análogo a mutation_audit); si baja del umbral, falla el JUEZ |
sí (opt-in) |
contracts/ |
Rubrics firmados: pre-complexity-agent, complexity-agent, task-author-agent, eval-agent (juez Tier 2) |
— |
Quickstart
pip install -r requirements.txt
# 1) Gate determinista sobre un task-contract de ejemplo (PASS)
python runners/task_gate.py examples/sandbox/task.md
# 2) Tests congelados (deterministas, sin LLM): gate + gobernanza L2 (Ed25519) + reglas tc_lint
python -m unittest tests.test_gates tests.test_l2_governance tests.test_tc_lint_rules -v
# 3) Linter de un task-contract
python runners/tc_lint.py examples/sandbox/task.md
Como hook de auto-validación en Claude Code
settings.json → hooks.PostToolUse con matcher Write|Edit:
{ "command": "python runners/complexity_gate.py" }
Cada archivo que el agente escribe se mide con el backend de su lenguaje (por extensión, o
--language en CLI); si una métrica entra en CRÍTICA (umbral firmado), el hook bloquea y pide
refactor. Determinista, sin tokens. Una extensión sin backend registrado es un no-op anunciado
(aviso por stderr, exit 0), nunca un fallo silencioso. Hoy el único backend es Python.
Instalación como paquete (console scripts)
Para usar ccdd-gate sin clonar ni rutas absolutas, instálalo como distribución (deja los scripts
ccdd-mcp, ccdd-lint, ccdd-gate, ccdd-measure en el PATH):
pipx install ccdd-gate # o: uvx ccdd-gate · o: pip install ccdd-gate
El modo desde el repo (
python runners/<x>.py) sigue funcionando para desarrollo. Nota: los datos de gobernanza (rubric/attestations bajocontracts/, schema en la raíz) se resuelven en el layout del repo / instalación editable (pip install -e .); el núcleo determinista (medir/lintar/gate/MCP) funciona en cualquier modo.
Como MCP
Con el paquete instalado, el .mcp.json no necesita clonar el repo ni cwd:
{ "mcpServers": { "ccdd": { "command": "ccdd-mcp" } } }
Desde el repo, copiá .mcp.json.example a .mcp.json. Tools (sin LLM):
measure_complexity(code)— métricas AST reales por función.complexity_rubric(agent)— el criterio gobernado (system/policies/thresholds) firmado.scan_guardrails(code, agent?, language?, filename?)— guardrails deterministas: secretos (texto-puro, igual en todo lenguaje), anidamiento (estructural, vía el backend del lenguaje),dsv_check(anti-alucinación por "drift", exige coincidencia exacta con HEAD local) y específicos por lenguaje opt-in (runners/guardrails_lang.yaml, p. ej.no-eval).agentevalúa contra ese contrato. Sinlanguage, Python.lint_task_contract(contract_text, test_code?)- valida un task-contract (anti-desvarío del modelo grande).scan_dependencies(code, deps_allowed?)- imports top-level de terceros NO permitidos (enforcement dedeps_allowed/ anti-slopsquatting). Determinista, sin LLM.check_signature(source, fn_name, expected_signature)- "" si la firma implementada coincide con la esperada (nombre + nombres de params en orden), o el desajuste. Determinista, sin LLM.check_purity(source, fn_name, target_line?)- operaciones impuras del cuerpo (gate-purity). Sin LLM.check_mutable_defaults(source, fn_name, target_line?)- params con default mutable (gate-mutdef). Sin LLM.check_bare_except(source, fn_name, target_line?)- líneas deexcept:desnudo (gate-bareexcept). Sin LLM.check_asserts(source, fn_name, target_line?)- líneas deassert(gate-assert). Sin LLM.check_none_cmp(source, fn_name, target_line?)- comparaciones con None por ==/!= (gate-nonecmp). Sin LLM.run_rules_gate(rules_path?, root?)- aplica los checks deterministas project-wide por glob desde unrules.yaml. Sin LLM.run_integration_gate(task_path)- veredicto PASS/FAIL unificado de un contrato YA EN DISCO (lint + aprobación de tests + tests congelados + complejidad ≤ budget), idéntico a la CLItask_gate.py. Parakind:groupcompone las hijas + el test de integración sobre los archivos reales (sin sandbox). El agente NO implementa: delega arun_ephemeral_agent.run_ephemeral_agent(task_path)- delega la implementación al modelo pequeño local y la valida contra el gate. El servidor fija modelo y endpoint; el LLM anfitrión solo pasatask_path(no elige el modelo). El operador puede elegir el modelo por entorno (CCDD_EXECUTOR_MODEL,CCDD_EXECUTOR_API) sin tocar la fuente; el LLM no. Default:qwen3-coder:480b-cloudvía Ollama (http://localhost:11434/v1).audit_composition(root?)- composición sin gatear project-wide; separa deuda de FORMA (composición ejercitada por el test del composer) de deuda de COMPORTAMIENTO (mock o test ausente).ok= sin deuda de comportamiento.audit_orphan_targets(root?)-.pyde implementación que no son target de ningún contrato (exime tests/__init__/datos puros). Para proyectos 100% CCDD.audit_annotations(root?)- nombres usados en anotaciones sin importar/definir, sobre todos los targets; caza bugs de portabilidad que Python 3.14 (lazy annotations) enmascara en runtime.mutation_audit(task_path)- fuerza del oráculo vía mutation testing determinista; un mutante sobreviviente delata un test débil. Opt-in (corre los tests por mutante).request_human_attestation(code, reason)- permite al agente pedir una excepción firmada cuando no puede reducir la complejidad por reglas de negocio.run_eval_gate(eval_path)- pilar de evals (Tier 1): veredicto determinista sobre el output NO determinista de un agente (dataset congelado + checks). Sin LLM.eval_rubric()- rúbrica firmada del juez Tier 2 (contratoeval-agent).judge_audit(eval_path, provider?)- acuerdo del juez Tier 2 vs golden set humano; si baja del umbral, el juez no es de fiar. Providerstub(determinista) por defecto.
Checklist de cierre (antes de dar una tarea por terminada): corré las cuatro auditorías —audit_composition, audit_orphan_targets, audit_annotations y mutation_audit— hasta ok:true. El gate de función no cubre composición, código huérfano, anotaciones ni la fuerza del oráculo; quedarse con la auditoría que da verde y declarar "todo en verde" es el modo de falla que la checklist existe para cerrar (y que el CI hace no-opcional).
Pilar de evals: gatear output NO determinista (Tier 1 + Tier 2 opt-in)
El gate de complejidad/tests verifica código (funciones con oráculo independiente). Pero un agente de producción (un bot de soporte, un asistente de research) produce texto/JSON no determinista que ese gate no cubre. El pilar de evals lo cierra sin renunciar al determinismo donde se puede, en dos niveles:
-
Tier 1 — checks deterministas, sin LLM (
eval_gate.py+eval_checks.py). Sobre cada caso de un dataset CONGELADO y firmado (cases_sha256, igual quetests_sha256): schema del output, contención/ausencia de términos,must_cite+ groundedness (toda cita apunta a una fuente existente → anti-alucinación), PII, y evaluación de trayectoria (tools requeridas/prohibidas,max_steps). Veredicto = función del budget:pass_rate ≥ pass_rate_miny violaciones duras ≤forbidden_violations_max. Mismo input → mismo veredicto. Muchos agentes (extracción, clasificación, routing) se gatean 100% aquí. -
Tier 2 — juez LLM ACOTADO, opt-in (
eval_judge.py+judge_audit.py). Solo para lo genuinamente subjetivo (coherencia, utilidad). El modelo se pinnea (temperature 0) y su veredicto no cuenta hasta pasarjudge_audit: el juez se calibra contra un golden set atestado por humano y debe alcanzaragreement ≥ agreement_min. Es a la calidad lo quemutation_audites al oráculo: no confía en el juez, lo mide. La única relajación de determinismo (el score por-corrida del LLM) queda acotada y auditada; cualquier deriva del modelo pinneado la cazajudge_auditen CI.
# Firmar el dataset (OK humano, congela los casos)
python runners/approve_eval_cases.py examples/eval/support-bot-refunds/eval.md
# Veredicto Tier 1 (sin LLM, reproducible)
python runners/eval_gate.py examples/eval/support-bot-refunds/eval.md
# Calibrar el juez Tier 2 contra el golden set (offline con provider stub)
python runners/judge_audit.py examples/eval/support-bot-refunds/eval.md
El eval-contract (front-matter YAML + cuerpo, espeja al task-contract) declara target,
agent_entry, dataset, budget, deterministic_checks y el bloque judge (opt-in). Ver
examples/eval/support-bot-refunds/ para el ejemplo end-to-end (agente determinista de juguete,
dataset firmado, schema y rúbrica).
El loop grande/pequeño (Stateless Feedback y Evolución CEFL)
El loop es stateless (sin estado) pero incorpora mecánicas evolutivas inspiradas en CEFL (Candidate Expansion and Freezing):
- Expansión Paralela: El orquestador no pide 1 intento; pide N candidatos paralelos (
--candidates 3). - Torneo de Complejidad (Freezing): Cada candidato se aísla y se valida contra los tests y el budget de complejidad. Si varios pasan, el Gate elige automáticamente el que tenga la menor puntuación matemática de complejidad, congelándolo como la respuesta definitiva.
- Feedback Masivo (Partial Success): Si todos los candidatos fallan, el sistema no reenvía código roto uno por uno. Agrupa las N soluciones fallidas junto a sus errores (stack traces) en un JSON combinado masivo. Esto permite al modelo en la siguiente iteración aprender cruzando los fracasos de todas sus rutas exploratorias, resolviendo problemas que un solo reintento jamás lograría.
# OFFLINE (sin modelo): stub que entrega 1 impl rota y 1 buena -> intento 1 FAIL, intento 2 PASS
python runners/orchestrator.py examples/sandbox/loop_demo/task.md \
--provider stub \
--stub examples/sandbox/loop_demo/_stub_bad.py \
--stub examples/sandbox/loop_demo/_stub_good.py --max-attempts 3
# CON MODELOS: el pequeño genera 3 vías paralelas; si todas fallan, escala al grande
python runners/orchestrator.py examples/sandbox/loop_demo/task.md \
--provider openai --model <modelo-chico> --candidates 3 \
--escalate-provider ollama --escalate-model <modelo-grande> --escalate-attempts 2
Providers: ollama, openai (LM Studio/vLLM, urllib stdlib), anthropic (SDK), y stub
(secuencia offline para probar la mecánica sin modelo).
task-contract (formato)
Front-matter YAML (machine-checkable) + cuerpo Markdown (prescriptivo). Ver
examples/sandbox/task.md y el rubric de autoría en contracts/task-author-agent/.
Regla central: especifica el contrato y los property-tests con oráculo independiente,
NO el algoritmo. Los tests se congelan y firman antes de que el implementador toque la tarea.
Campo target_line (opcional, desambiguación). El gate de complejidad resuelve la función
objetivo por nombre. Si el target tiene varias funciones/métodos homónimos (p. ej. set en
varias clases), declara target_line: N (la línea de la def correcta) para que mida esa y no otra.
Sin desambiguador y con >1 def del nombre, el gate devuelve INVALID (ambiguo) en vez de medir la
última en silencio (issue #41). Con un solo match el campo es innecesario (comportamiento idéntico).
Campo enforce_deps (opcional, anti-slopsquatting). Si enforce_deps: true, el gate corre la
etapa gate-deps: flaggea los imports top-level del target que no estén en deps_allowed (ni en
la stdlib) y falla con stage: gate-deps. Opt-in (default off): los contratos que no lo declaran
no cambian. Limitación actual: trata como "tercero" cualquier import no-stdlib que no esté en
deps_allowed, así que con enforce_deps los módulos locales del propio proyecto deben listarse en
deps_allowed (la exención automática de módulos locales queda como mejora futura). Solo Python por ahora.
Conformidad de firma (etapa gate-signature, default-on). El gate compara la firma IMPLEMENTADA
con la signature del contrato (nombre + nombres de parámetros en orden; ignora anotaciones,
defaults y retorno) y falla con stage: gate-signature si difieren — caza el drift de firma que
rompe a los callers. Es default-on: no requiere campo. Solo Python (compara vía AST).
Gates de antipatrones opt-in (default-off, Python, vía AST). Cada uno corre solo si el contrato
declara su campo; sin él, el contrato no cambia. Todos fallan con su propio stage:
| Campo | Etapa | Falla si la función… |
|---|---|---|
pure: true |
gate-purity |
tiene operaciones impuras (print/open/eval/exec/__import__/input, global/nonlocal, import interno) |
forbid_mutable_defaults: true |
gate-mutdef |
tiene params con default mutable ([]/{}/set()/list()/dict()) |
forbid_bare_except: true |
gate-bareexcept |
tiene un except: desnudo (sin tipo) |
forbid_assert: true |
gate-assert |
usa assert (desaparece con python -O) |
forbid_none_eq: true |
gate-nonecmp |
compara con None usando ==/!= en vez de is/is not |
Cada uno honra target_line para funciones homónimas y tiene su tool MCP (check_purity,
check_mutable_defaults, check_bare_except, check_asserts, check_none_cmp).
Reglas project-wide por glob (rules_gate). Los gates de antipatrón de arriba se disparan
por contrato. Para aplicarlos a TODO el repo sin contratos, runners/rules_gate.py lee un
rules.yaml declarativo (lista de {check, files}) y corre el check determinista sobre cada función
de los archivos que matchean el glob — política de repo, no solo por función gateada. La idea del
formato declarativo + glob está tomada de autorules, pero
el árbitro es AST determinista, no un LLM (autorules usa un juez LLM; ccdd-gate no). Ver
examples/rules.yaml.example y la evaluación completa en
docs/evaluations/autorules.md.
python runners/rules_gate.py rules.yaml [root] # exit 0 ok · 1 violaciones · 2 config inválida
Campo language (opcional, multi-lenguaje). Por defecto python. Con language: python
la firma se valida con el AST nativo (preciso). Para otros lenguajes (typescript, javascript,
go, …) tc_lint valida la firma por aridad genérica (cuenta de parámetros top-level y
extracción de nombre, respetando ()[]{}<> y comillas) y emite el warning tc-signature-generic
para señalar que no hay parser nativo. params_max y el resto de reglas se aplican igual.
Sin el campo, el comportamiento es idéntico al actual (Python).
Conformancia multi-lenguaje
fixtures/conformance/ define un oráculo congelado de las 4 métricas (fixtures equivalentes
por lenguaje + valores esperados). Todo backend debe reproducirlo: Python es el baseline y el
backend TypeScript/JS (tree-sitter) pasa la suite con métricas estructurales idénticas
(cyclomatic/nesting_depth/parameter_count); solo function_length diverge por formato y se
fija por-lenguaje. Un backend nuevo no se acepta hasta pasar tests/test_conformance.py. Ver
fixtures/conformance/README.md.
Multi-lenguaje hoy: Python nativo (sin deps) + TS/TSX/JS vía tree-sitter (dep opcional:
pip install tree_sitter tree_sitter_typescript). El gate, el hook y measure_complexity miden
.ts/.js igual que .py cuando la dep está instalada; si no, esos archivos son no-op anunciado.
Integración GitHub (opcional, integrations/github/)
Capa adaptadora opcional: el sustrato determinista no depende de GitHub. Sin ella, todo
funciona en local. Usa gh CLI; tokens por entorno, nunca en el repo.
reporter.py— toma el JSON detask_gate/complexity_gatey genera un comentario Markdown determinista (PASS/FAIL, métricas vs budget, motivo). Idempotente: actualiza un comentario "marcado" en vez de spamear. Offline imprime el Markdown;--postlo publica víagh.ci_gate.py+.github/workflows/ccdd-gate.yml— GitHub Action: en cada PR descubre los task-contracts afectados (el.mdo sutarget), corretc_lint+task_gatey bloquea el merge (exit 1) si el veredicto no pasa; publica el resumen como comentario idempotente vía el Reporter. Además corre no-opcionalmenteaudit_compositionyaudit_annotationsproject-wide ymutation_auditsobre los contratos afectados: composición sin gatear, anotaciones sin importar o mutantes sobrevivientes también ponen el check en rojo (lo que el autor tiende a saltar cuando es opt-in, acá no se puede saltar). Sin LLM, sin secretos (usa elGH_TOKENdel runner). Copiable a un repo consumidor: copia.github/workflows/ccdd-gate.ymleintegrations/github/(o vendoriza/instala ccdd-gate) y activa branch protection sobre el checkccdd-gate.scaffold.py— genera el esqueleto de un task-contract desde un issue (--issue owner/repo#No--from-jsonoffline). Captura la intención (título/cuerpo/labels) con placeholdersTODO; el resultado es incompleto a propósito (tc_lintlo marca, no falsamente verde).lifecycle.py— conecta el orquestador con el ciclo de vida del issue: un issueccdd:readycon gate verde abre un PR enlazado (Closes #N) y pasa accdd:in-review; si escala →ccdd:escalated; si ni el grande pasa →ccdd:needs-split. El loop del orquestador no sabe de GitHub (recibe un callback opcionalon_result); sin él, corre igual en local. Transiciones de label deterministas y reversibles.decompose.py— materializa task-contracts atómicos como sub-issues de un issue padre (epic/feature), con vínculo bidireccional y marker idempotente (re-ejecutar no duplica). No decide la descomposición (la decide el autor): solo la materializa.link.py— vínculo bidireccional contrato↔issue:status --contract(estado + labels) ostatus --issue owner/repo#N(contratos que lo referencian), ysync-labels(refleja el estado como labelsccdd:*, idempotente, sin pisar labels ajenas). El campoissuedel front-matter es opcional;tc_lintvalida su formato (reglatc-issue-ref) sin romper contratos sin él.
Benchmarks
Ver BENCHMARKS.md. En resumen: el gate determinista cuesta 0 tokens y
su lógica es sub-milisegundo (python benchmarks/bench_gate.py). La economía grande/pequeño
está medida y honestamente etiquetada como ilustrativa — gana por reuso/volumen, no en el
one-shot trivial (ahí es más caro).
Honestidades (léelas antes de creerle a nadie)
- El ahorro de tokens es condicional, no universal. En una tarea trivial de un tiro,
este flujo puede salir más caro que solo llamar al modelo grande. Gana por volumen,
reuso y dificultad. Medilo vos con
runners/measure.py; no te fíes del titular. - El gate es tan fuerte como sus property-tests. Tests laxos → el modelo pequeño pasa
basura. La auditoría del modelo grande (
test_audit.py) y el oráculo independiente son lo que hace que el veredicto signifique algo. task_gateejecuta los tests. En local con tus modelos es seguro; para correr código ajeno usá un sandbox aislado (contenedor), no el host.- Auditar tests requiere un modelo grande. Un modelo de ~12B como auditor tiende a aprobar tests rotos. Implementar lo hace bien; auditar, no.
Licencia
MIT © 2026 Mauricio Perera. Incluye ccdd.py y ccdd_context.schema.json del proyecto
CCDD (mismo autor, MIT), con una única adaptación
para uso standalone: ccdd.py resuelve su schema junto a sí mismo (upstream lo busca en el
directorio padre). Publicado as-is, sin garantía ni soporte.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ccdd_gate-0.1.0.tar.gz.
File metadata
- Download URL: ccdd_gate-0.1.0.tar.gz
- Upload date:
- Size: 126.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34c8b4040c3d0023527505a9b1bd2a580d91e2b56c81288085f2117d54897bbc
|
|
| MD5 |
8ba75d1f64a7b7fda7b5637f17307f4d
|
|
| BLAKE2b-256 |
11a3d76ba45aecd0b423f021829c5ed629a1ad50c312738765eb0e0f20dd01fe
|
File details
Details for the file ccdd_gate-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ccdd_gate-0.1.0-py3-none-any.whl
- Upload date:
- Size: 108.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f3356fb78d0f587b33cb9b1693cdb47886e6cebbe732974f12a3056a30f7415
|
|
| MD5 |
d6778a62af279574b479617328f07fdd
|
|
| BLAKE2b-256 |
2525228c29f767f85f2855bc479ad48efa8e4a586013141a4da5bfad3953e354
|