Saltar al contenido
Tórculo1.0 · borrador de trabajo

Dos implementaciones, los mismos casos

Conformidad

La batería de conformidad de Tórculo: los casos que una implementación debe pasar para llamarse conforme, y el último informe.

Este texto está en inglés.

The suite every Tórculo implementation runs. A case is a small JSON file with an input and the exact expected output; an implementation conforms to a kind of case when it passes every non-pending case of that kind. Normative text: spec/SPEC.md. Suite version and case count: manifest.json. Changes: CHANGELOG.md.

Every pliego of the suite carries music and sound design (BANDA, EFECTOS, MEZCLA, MÚSICA, AMBIENTE, ESPACIO and sonido: effects). The sounds are synthesized by tools/sonido.py with the Python standard library and the canon's randomness: the same bytes on every machine, dedicated to the public domain (CC0 1.0). They are not committed; the generator and the runner make them (their SHA-256 are in the manifest).

Layout

PathWhatMade by
pliegos/*.mesathe pliegos: one per area of the language and per profilehand
pliegos/errores/*.mesaone broken rule per pliego, named after what it breakshand
pliegos/sonido/music cues (banda/) and effects and ambiences (efectos/)tools/sonido.py
manual/lee.jsonthe expected diagnostics of every pliego, written by handhand
expected/ir/*.ir.jsonthe frozen IR of the reference implementationtools/generar.py
expected/huella/*.jsonthe fingerprints (§13.4) and soundtrack reports of the reference interpretertools/generar.py --huellas
canon/vectores.jsonthe canon's test vectors, computed with independent integer arithmetictools/generar.py
laminas/*.dibujo.jsonthe drawings whose láminas every producer must reproduce byte for bytecopied from pluma/pruebas/referencia
tomas/*.take, tomas/fuentes/*.pytakes recorded by the engine fork, and the scenes that made themthe engine
tomas/invalidas/*.takeone broken rule per taketools/generar.py
mesapack/*.mesapacka minimal valid package and one broken rule per packagetools/generar.py
materias/*.wgslshaders that break the pass conventiontools/generar.py
cases/*.jsonone case per filetools/generar.py
informe.jsonthe last report of the runner against the reference implementationstools/ejecutar.py

The oracles

Independent readers written from the specification, Python standard library only:

ToolChecks
tools/jcs.pyRFC 8785 canonical JSON (self-test: python3 tools/jcs.py)
tools/ir.pythe normative projection of an IR (§10.6)
tools/toma.pytakes (§19); codes T001 to T007
tools/lamina.pyláminas (§17); codes L001 to L011
tools/mesapack.pypackages (§14); codes P001 to P009
tools/materias.pythe pass convention (§18); codes M001 to M006
tools/huella.pyfingerprints of a film (§13.4) and their tolerant comparison
tools/adaptadores/manim_saorin.pythe adapter to the reference implementation of the language

Regenerating and running

python3 conformance/tools/generar.py             # everything except the fingerprints
python3 conformance/tools/generar.py --huellas   # also renders the fingerprints (heavy)
python3 conformance/tools/ejecutar.py            # the quick classes (about a minute)
python3 conformance/tools/ejecutar.py --pesado   # everything: fingerprints, soundtrack, Rust láminas, package round trip

Requirements: Python 3.11 or later; Node 22 or later (TypeScript canon and the WebAssembly pen); rustc (Rust canon); ffmpeg (fingerprints); the Python with which manim-saorín runs (MESA_PY, by default the Homebrew Manim one) and its folder (MESA_IMPL); the pen's Python (TORCULO_PLUMA_PY). Heavy work goes through tools/pesado.

How expectations are made

So that nobody has to trust a single implementation:

  • Diagnostics are written by hand in manual/lee.json. The generator refuses to write a case if the reference disagrees, unless the case is marked pending with its reason.
  • Vocabularies are extracted from the parser (spec/vocabularios/extrae.py): the specification is that table, and the case checks the parser still says it.
  • IRs are the reference's, reviewed and frozen. Other compilers are held to the normative projection; the reference, to the whole IR.
  • Closure and mirror are properties: the runner computes both sides.
  • Canon vectors are computed in generar.py with integer arithmetic written again, not with the generated canon.
  • Láminas: their hashes come from the WebAssembly build of the pen (pluma/pruebas/referencia/_laminas.json); Python and Rust must give the same bytes.
  • Takes, packages, shaders: one broken file per rule, with the code the oracle must give; the generator stops if the oracle disagrees.
  • Fingerprints and soundtrack are the reference interpreter's, on the reference machine; they are compared with tolerance (§13.4) and the soundtrack against the targets of §8.2 (−14 LUFS ± 1 LU, true peak at most −1 dBTP, the cues and counts).

Case format

{"id": "lee-errores-afecto", "kind": "lee", "input": {"pliego": "pliegos/errores/afecto.mesa"},
 "expect": {"valido": false, "errores": ["E010"], "avisos": ["W113"]}}

id equals the file name; paths are relative to conformance/. A case MAY carry "pendiente": "reason": a known deviation of the reference implementation (SPEC Appendix D), reported apart.

kindinputexpectpasses when
vocabulariothe vocabularies fileigualesextracting from the parser gives the same file
leepliegovalido, errores, avisossame validity and the same sets of codes
irpliegoir (path), sha256, proyeccion_sha256the normative projection's fingerprint matches; for the reference, the whole IR too
cierrepliegoiguales_modulo_procedencia, se_quitacanon(compile(p)) == canon(compile(escribe(p)))
espejopliegoefectivo_igualthe effective workshop and hand of p, parte(p) and funde(parte(p)) are equal
canon_azarvectores, lenguaigualesthe language's canon gives every vector exactly
canon_paletavectores, lenguacoloresevery colour of the generated file matches canon.toml
laminadibujo, implementacionsha256, validathe packed lámina has that hash and validates
tomatomavalida, resumen or codigothe reader gives that summary, or rejects with that code
mesapackmesapackvalido, erroresthe validator gives exactly those codes
mesapack_referenciapliegovalido, erroresthe packager's package of that pliego validates
materiawgsl, modulosconforme, erroresthe checker gives exactly those codes
huellapliego, motor, calidadhuella, toleranciathe rendered film's fingerprint matches
bandapliego, motor, calidadloudness, true peak, cues, countsthe soundtrack report meets them

Adapters

The runner talks to an implementation through an adapter (tools/adaptadores/). An adapter for another compiler offers the same functions as manim_saorin.py: ir(pliego), lee(pliego) returning codes, escribe, parte, funde, taller, and, for an interpreter, toca_gx(pliego, out) writing the video, the master and the soundtrack report.

The report

ejecutar.py prints a one-line summary and writes informe.json: the suite version and cases_sha256, the date, the implementations, the totals (pasa, falla, pendiente, omitido), the totals per kind, and one result per case with its detail when it did not pass.

El último informe

torculo-conformance 0.2.0 · 15 de octubre de 2026 a las 14:13 · 62,8 s

89 pasa 0 falla 5 pendiente 8 omitido

Qué se ha probado

ParteImplementación
lenguamanim-saorin · 1.0.0b1 · MESA v2 beta · 3f34801
canoncanon/gen (python, typescript, rust, wgsl, css)
laminaspluma (python, wasm, rust)
tomasconformance/tools/toma.py sobre tomas del fork
mesapackconformance/tools/mesapack.py y `mesa empaqueta`
materiasconformance/tools/materias.py sobre materias/shaders

Por clase de caso

Clasepasafallapendienteomitido
banda2
canon_azar3
canon_paleta5
cierre31
espejo1
huella2
ir12
lamina63
lee313
materia10
mesapack10
mesapack_referencia1
toma8
vocabulario1
Los 102 casos
CasoClaseEstadoDetalle
banda-estampasbandaomitidoclase pesada: con --pesado
banda-oficiobandaomitidoclase pesada: con --pesado
canon-azar-pythoncanon_azarpasa
canon-azar-rustcanon_azarpasa
canon-azar-typescriptcanon_azarpasa
canon-paleta-csscanon_paletapasa
canon-paleta-pythoncanon_paletapasa
canon-paleta-rustcanon_paletapasa
canon-paleta-typescriptcanon_paletapasa
canon-paleta-wgslcanon_paletapasa
cierre-dirigidocierrepasa
cierre-escenacierrepasa
cierre-servilletacierrependienteLa referencia rompe el cierre en una servilleta con banda: `mesa escribe` reescribe el preámbulo y pierde BANDA, EFECTOS, MEZCLA, MÚSICA y AMBIENTE (la IR escrita ya no suena). [/banda: sonido/banda ≠ None; /beats[0]/aspecto/ambiente: amb sala bucle ≠ None; /beats[0]/aspecto/musica: 1M1 ≠ None; /beats[1]/aspecto/ambiente: amb sala bucle ≠ None; /beats[1]/aspecto/musica: 1M1 ≠ None; /beats[2]/aspecto/ambiente: amb sala bucle ≠ None; /beats[2]/aspecto/musica: 1M1 ≠ None; /beats[3]/aspecto/ambiente: amb sala bucle ≠ None]
cierre-tallercierrepasa
espejo-tallerespejopendienteLa referencia rompe la ley del espejo con la MANO de este pliego: importada desde `manos/firme.mano`, `toca la truca: sí` se lee como `no`; escrita en línea, `precisión alta` queda como una clave sin normalizar al lado de `precision alta`; y `parte` pierde el nombre de la sección (`#TALLER collage` → `#TALLER`). [MANO efectivo distinto: toca la truca: no; toca la truca: si]
huella-estampashuellaomitidoclase pesada: con --pesado
huella-oficiohuellaomitidoclase pesada: con --pesado
ir-aspectoirpasa
ir-bandairpasa
ir-camarairpasa
ir-cartelirpasa
ir-dirigidoirpasa
ir-escenairpasa
ir-estampasirpasa
ir-oficioirpasa
ir-oidoirpasa
ir-raccordirpasa
ir-servilletairpasa
ir-tallerirpasa
lamina-manicula-pythonlaminapasa
lamina-manicula-rustlaminaomitidoRust: con --pesado
lamina-manicula-wasmlaminapasa
lamina-nota-aqui-pythonlaminapasa
lamina-nota-aqui-rustlaminaomitidoRust: con --pesado
lamina-nota-aqui-wasmlaminapasa
lamina-tintero-pythonlaminapasa
lamina-tintero-rustlaminaomitidoRust: con --pesado
lamina-tintero-wasmlaminapasa
lee-aspectoleepasa
lee-bandaleepasa
lee-camaraleepasa
lee-cartelleepasa
lee-dirigidoleepasa
lee-errores-accionleepasa
lee-errores-afectoleepasa
lee-errores-ambienteleepasa
lee-errores-ambiguedadleepasa
lee-errores-anclaleepasa
lee-errores-bestiario-ausenteleepasa
lee-errores-collageleepasa
lee-errores-color-vozleepasa
lee-errores-cueleepasa
lee-errores-dibujoleepasa
lee-errores-efectoleepasa
lee-errores-epocaleepasa
lee-errores-espacioleepasa
lee-errores-eventoleepasa
lee-errores-funcionleepasa
lee-errores-gritosleepasa
lee-errores-letra-preambuloleependienteLa referencia acepta `LETRA` (una línea de clip) en el preámbulo sin error y la descarta en silencio: el signo no llega a la IR. Por la ley de las tres sedes (§3) una línea fuera de su sitio es un error (E090), nunca una línea que desaparece. [esperado {'avisos': ['W113'], 'errores': ['E090'], 'valido': False}, da {'valido': True, 'errores': [], 'avisos': ['W113', 'W124']}; mensajes: ['sin «silencio final» declarado (se aplica 3)', 'línea 12 · página vacía · b01: el beat corta a un cuadro nuevo y no po']]
lee-errores-letreroleepasa
lee-errores-movimientoleepasa
lee-errores-pantallaleepasa
lee-errores-pieza-sin-repartoleepasa
lee-errores-reservadaleependienteLa referencia acepta `REPARTO nota: …` sin error y luego trata `nota:` como directiva (avisa «clip vacío»). §5.5 y §6.4 exigen E021 al declarar un hablante con una palabra reservada. [esperado {'avisos': ['W113'], 'errores': ['E021'], 'valido': False}, da {'valido': True, 'errores': [], 'avisos': ['W113', 'W116']}; mensajes: ['línea 12 · b01: clip vacío', 'sin «silencio final» declarado (se aplica 3)']]
lee-escenaleepasa
lee-estampasleependienteLa referencia avisa «clip vacío» (W116) en un clip cuyo único contenido es un signo (`LETRA`). Según §8.3 un signo es una pieza y el clip no está vacío. [esperado {'avisos': ['W112'], 'errores': [], 'valido': True}, da {'valido': True, 'errores': [], 'avisos': ['W112', 'W116']}; mensajes: ['porcentaje pobre 82 % (sano: ≥85 %). 7 líneas con cifras; el pliego di', 'línea 39 · b03: clip vacío']]
lee-oficioleepasa
lee-oidoleepasa
lee-raccordleepasa
lee-servilletaleepasa
lee-tallerleepasa
materia-acuarelamateriapasa
materia-difuminadomateriapasa
materia-papelmateriapasa
materia-pincelmateriapasa
materia-risografiamateriapasa
materia-rota-m001materiapasa
materia-rota-m004materiapasa
materia-rota-m005materiapasa
materia-tejidomateriapasa
materia-transicionmateriapasa
mesapack-formato-futuromesapackpasa
mesapack-hash-rotomesapackpasa
mesapack-ida-y-vuelta-dirigidomesapack_referenciaomitidoclase pesada: con --pesado
mesapack-minimomesapackpasa
mesapack-no-zipmesapackpasa
mesapack-ruta-peligrosamesapackpasa
mesapack-sidecar-absolutomesapackpasa
mesapack-sin-declararmesapackpasa
mesapack-sin-manifiestomesapackpasa
mesapack-sin-pliegomesapackpasa
mesapack-sin-versionesmesapackpasa
toma-banotomapasa
toma-estampatomapasa
toma-invalida-codigo-desconocidotomapasa
toma-invalida-cortadatomapasa
toma-invalida-post-fuera-de-sitiotomapasa
toma-invalida-sin-starttomapasa
toma-invalida-tras-endtomapasa
toma-invalida-version-upstreamtomapasa
vocabulario-parservocabulariopasa

informe.json