Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
- run: node scripts/verify-manifest-consistency.mjs
- run: node scripts/verify-cargo-examples.mjs
- run: node scripts/verify-chapter-anatomy.mjs
- run: node scripts/verify-review-packet-coverage.mjs
- run: node scripts/verify-editorial-status.mjs
- run: cargo fmt --check
- run: cargo clippy --all-targets --all-features -- -D warnings
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ node scripts/verify-course-links.mjs
node scripts/verify-manifest-consistency.mjs
node scripts/verify-cargo-examples.mjs
node scripts/verify-chapter-anatomy.mjs
node scripts/verify-review-packet-coverage.mjs
node scripts/verify-editorial-status.mjs
```

Expand Down
1 change: 1 addition & 0 deletions docs/compuertas-automaticas.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ un estado editorial superior.
| `node scripts/verify-manifest-consistency.mjs` | Que `course.manifest.json` mantenga identidad, orden, unicidad y rutas derivadas del número y slug de cada capítulo. | Número duplicado, slug inválido, documento mal nombrado o ruta inconsistente. | Joel decide si el manifiesto representa el contrato correcto para `academy-web`. |
| `node scripts/verify-cargo-examples.mjs` | Que todos los ejemplos `.rs` de `examples/` estén declarados explícitamente en `Cargo.toml` y que cada ruta declarada exista. | Ejemplo sin declarar, ruta inexistente, nombre duplicado o ruta duplicada. | Joel decide si el ejemplo enseña el concepto con claridad suficiente. |
| `node scripts/verify-chapter-anatomy.mjs` | Que cada capítulo conserve la anatomía editorial esperada antes de revisión humana. | Falta concepto, problema, alternativas, justificación, invariantes, modelo Rust, ejemplo, práctica o cierre editorial. | Joel decide si la explicación es correcta, suficiente y aprobable. |
| `node scripts/verify-review-packet-coverage.mjs` | Que el paquete de revisión humana cubra todos los capítulos y sus artefactos principales. | Falta un capítulo, ruta, comando de compuerta o frontera editorial. | Joel decide el resultado de la revisión; la compuerta solo evita omisiones. |
| `node scripts/verify-editorial-status.mjs` | Que ningún capítulo se marque como `reviewed` ni `published` por automatización. | Estado editorial elevado sin revisión humana explícita. | Solo Joel puede aprobar revisión o publicación de capítulos. |
| `cargo fmt --check` | Que el código Rust conserve formato estándar. | Archivo Rust fuera de formato. | No sustituye criterio sobre legibilidad pedagógica. |
| `cargo clippy --all-targets --all-features -- -D warnings` | Que biblioteca, pruebas y ejemplos no acumulen advertencias relevantes. | Warning de Clippy o patrón de código riesgoso. | Joel decide si una excepción futura requiere explicación curricular. |
Expand Down
1 change: 1 addition & 0 deletions docs/publicacion-candidata.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Antes de considerar este corte como listo para revisión humana, deben pasar:
- `node scripts/verify-manifest-consistency.mjs`;
- `node scripts/verify-cargo-examples.mjs`;
- `node scripts/verify-chapter-anatomy.mjs`;
- `node scripts/verify-review-packet-coverage.mjs`;
- `cargo fmt --check`;
- `cargo clippy --all-targets --all-features -- -D warnings`;
- `cargo test --all-targets`;
Expand Down
100 changes: 100 additions & 0 deletions scripts/verify-review-packet-coverage.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { readFileSync } from "node:fs";
import { join } from "node:path";

const root = join(import.meta.dirname, "..");
const manifest = JSON.parse(
readFileSync(join(root, "course.manifest.json"), "utf8"),
);
const packetPath = join(root, "docs", "paquete-revision-humana.md");
const packet = readFileSync(packetPath, "utf8");
const failures = [];

function fail(message) {
failures.push(message);
}

const requiredGlobalSections = [
"# Paquete de revisión humana",
"## Frontera de decisión",
"## Compuertas antes de revisar",
"## Preguntas por capítulo",
"## Capítulos",
"## Resultado de la revisión",
];

for (const section of requiredGlobalSections) {
if (!packet.includes(section)) {
fail(`falta sección global: ${section}`);
}
}

for (const command of [
"node scripts/verify-course-links.mjs",
"node scripts/verify-manifest-consistency.mjs",
"node scripts/verify-cargo-examples.mjs",
"node scripts/verify-chapter-anatomy.mjs",
"node scripts/verify-editorial-status.mjs",
"cargo fmt --check",
"cargo clippy --all-targets --all-features -- -D warnings",
"cargo test --all-targets",
"cargo test --doc",
"cargo bench --all-targets",
"git diff --check",
]) {
if (!packet.includes(command)) {
fail(`falta comando de compuerta: ${command}`);
}
}

for (const chapter of manifest.chapters) {
const prefix = String(chapter.number).padStart(2, "0");
const heading = `### ${prefix}. ${chapter.title}`;
const headingIndex = packet.indexOf(heading);

if (headingIndex === -1) {
fail(`${chapter.title}: falta encabezado ${heading}`);
continue;
}

const nextHeadingIndex = packet.indexOf("\n### ", headingIndex + heading.length);
const chapterSection = packet.slice(
headingIndex,
nextHeadingIndex === -1 ? packet.length : nextHeadingIndex,
);

for (const [field, label] of [
["document", "Documento"],
["exercises", "Ejercicios"],
["costs", "Costos"],
["module", "Módulo Rust"],
["example", "Ejemplo"],
["tests", "Tests"],
["diagram", "Diagrama"],
]) {
const expectedLine = `- ${label}: \`${chapter[field]}\``;

if (!chapterSection.includes(expectedLine)) {
fail(`${chapter.title}: falta ${expectedLine}`);
}
}

if (!chapterSection.includes("- Revisión humana:")) {
fail(`${chapter.title}: falta criterio de revisión humana`);
}
}

if (!packet.includes("`reviewed`") || !packet.includes("`published`")) {
fail("el paquete debe conservar explícita la frontera reviewed/published");
}

if (failures.length > 0) {
console.error("Paquete de revisión humana incompleto:");
for (const failure of failures) {
console.error(`- ${failure}`);
}
process.exit(1);
}

console.log(
`Paquete de revisión humana verificado: ${manifest.chapters.length} capítulos cubiertos.`,
);
Loading