name: seo-build-report description: Use AFTER the 8 Phase 8 section skills (/seo-section-foda, /seo-section-tech-audit, /seo-section-history, /seo-section-ai-audit, /seo-section-competitive, /seo-section-benchmarks, /seo-section-context, /seo-section-action-plan) have written their JSON slices to ~/Documents/punto-rojo-clients/{slug}/sections/. Optionally consumes content-strategy.json (Phase 9 — alimenta sec-16 §11.3 Matriz Cluster × Etapa × Disciplinas, v3 redesign 2026-05-12; deprecó sec-20 standalone). This is a THIN ORCHESTRATOR that composes the slices into the assembled JSON consumed by report-builder/generate-report.js. It does NOT measure data — it reads slices from disk, deep-merges them, and renders the single-file HTML deliverable.
Este skill es un ORQUESTADOR THIN con 7 fases secuenciales (0..6). NO hace measurements: lee 7 slices de disco, los compone, llama 1 CLI.
PROHIBIDO:
- Llamar Ahrefs / GSC / GA4 / DataForSEO / diagnostic-mcp directamente. Toda la data
ya vive en los slices
~/Documents/punto-rojo-clients/{slug}/sections/*.json. Si un slice falta o esta stale, STOP / WARN — NO regenerar la data inline. - Inventar data para campos que ningun slice cubre (ej. access_requirements,
onboarding_checklist). Usar
{ available: false }o array vacio para que el template degrade graceful. - Pushear a git sin confirmacion EXPLICITA del Lead (Fase 5).
- Persistir o copiar archivos al pr-toolkit con working tree dirty — abortar y pedir commit/stash primero.
- Saltar fases o colapsar multiples fases en una sola respuesta.
OBLIGATORIO:
- Operador = userEmail prefix del environment (ej: nico.m@puntorojo.com → "Nico").
NUNCA usar
cliente-CLAUDE.md.Leadcomo nombre del operador. Vershared/skill-execution-protocol.md§Regla 6. - Validar slug + period al inicio (Fase 0) — si falla, STOP.
- Respetar checkpoints del Lead en Fase 3 (pre-render), el gate pre-upload review (entre Fase 4 y Fase 5) y Fase 5 (pre-push).
- Citar la fuente de cada slice (
sections/foda.json,sections/context.json, etc.). - Si action-plan slice no existe → STOP con
"Run /seo-section-action-plan first."(skill 8/8 shipped v3.35.0 — slice REQUIRED igual que las otras 7). ⚠️ Fix F-07 (review 2026-06): el flag--no-action-planque se documentaba acá NO existe en ningún código —compose-assembled.cjstrata action-plan como REQUIRED (exit 1 si falta). Si falta el slice, correr/seo-section-action-planprimero.
Protocolo: shared/skill-execution-protocol.md Context engineering: shared/context-engineering.md (Patron 5 process-and-discard)
/seo-build-report — Orquestador thin de slices Phase 8
Objetivo
Componer los 7-8 JSON slices Phase 8 en un assembled JSON canonico (shape de
samples/chedraui-sample.json) y disparar generate-report.js para producir el
HTML profesional single-file.
Thin orchestrator: NO mide nada. NO llama APIs externas. NO consume
consolidated_json del backend. Las skills /seo-section-* ya hicieron el
trabajo pesado y dejaron sus slices en disco.
Modelo recomendado: Sonnet (orquestacion + merge + 1 subprocess call — ningun razonamiento pesado).
Entregables:
- HTML local en
report-builder/output/{slug}-diagnostico-{period}.html— share-able por email/drive a clientes externos. - (Opcional) URL hosted
https://pr-toolkit.puntorojo.com/reports/{slug}/{period}— auth-gated@puntorojo.com, para equipo interno.
Diferencia vs /seo-reporte: /seo-reporte hace consultas ad-hoc de
performance y resuelve findings pendientes. Este skill empaqueta los slices
ya producidos en un entregable visual profesional. Son complementarios.
Inputs
| Parametro | Tipo | Default | Descripcion |
|---|---|---|---|
client_slug |
string (required) | — | kebab-case del cliente (ej: chedraui). Regex /^[a-z0-9][a-z0-9-]*$/ |
period |
string (required) | current month | YYYY-MM del periodo del reporte. Regex /^\d{4}-\d{2}$/ |
--no-action-plan |
ELIMINADO (F-07 review 2026-06) | — | Documentado históricamente como DEV-ONLY pero nunca existió en código. action-plan es REQUIRED en compose-assembled.cjs. Para iterar en dev sin slice real, generar un stub con /seo-section-action-plan --sample |
--no-content-strategy |
flag (optional) | false | Skip explícito del slice content-strategy (Phase 9 — alimenta sec-16 §11.3 Matriz Cluster × Etapa × Disciplinas). Cuando NO se usa el flag y el slice EXISTE en disco → se consume + cross-validator obligatorio en Phase 5 + matriz §11.3 renderiza con clusters reales. Cuando se usa el flag o el slice NO existe → §11.3 simplemente NO renderiza (cero degradación visible — sec-16 mantiene P1-P4 intactos). Apropiado para clientes sin scope content/links o que aún no corrieron /seo-content-strategy. v3 redesign 2026-05-12: sec-20 standalone deprecada, integración total a sec-16. |
--pdf |
flag (optional) | false | Placeholder — PDF aun no soportado. Responder que queda queued y continuar con HTML |
Invocacion esperada del Lead:
/seo-build-report chedraui 2026-04
/seo-build-report chedraui 2026-04 --no-content-strategy (cliente sin content/links scope o slice no generado aún)
/seo-build-report chedraui 2026-04 --pdf (warning: PDF aún no soportado, fallback a HTML)
Prerequisitos
- Carpeta del cliente en
~/Documents/punto-rojo-clients/{client_slug}/concliente-CLAUDE.md+intelligence/*.md. - Slices en
{cliente}/sections/:- REQUERIDOS (8) Phase 8 — si falta cualquiera, STOP con
"Run /seo-section-{name} first.":foda.json(1/8),tech-audit.json(2/8),history.json(3/8),ai-audit.json(4/8),competitive.json(5/8),benchmarks.json(6/8),context.json(7/8),action-plan.json(8/8).
- OPCIONAL Phase 9 —
content-strategy.json. Si EXISTE → se consume + cross-validator obligatorio + alimenta sec-16 §11.3 Matriz Cluster × Etapa × Disciplinas (v3 redesign 2026-05-12). Si NO existe → §11.3 simplemente no renderiza (sec-16 queda con P1-P4 sin matriz; cero degradación visible). No bloquea el reporte. Generado por/seo-content-strategyv3. - action-plan es REQUIRED — sin bypass (el flag
--no-action-plandocumentado históricamente nunca existió en código; F-07 review 2026-06).
- REQUERIDOS (8) Phase 8 — si falta cualquiera, STOP con
- Node 20+ +
report-builder/node_modules(si falta:cd report-builder && npm install). - Repo pr-toolkit (solo si Lead elige upload) — default
C:\Users\nicko\OneDrive\Escritorio\Proyectos\Punto-Rojo\pr-toolkit\o$PR_TOOLKIT_PATH.
Flujo general
Inicio → Inputs + validacion →
Fase 0: Context load (cliente-CLAUDE.md + actividad.md + intelligence/*)
Fase 1: Verify slices exist + freshness check (warn si >30 dias)
+ Validate cada slice via su validator (lib/{name}-validator.js)
+ Cross-slice consistency: action-plan ↔ content-strategy (si existe slice opcional)
Fase 2: Compose assembled JSON (deep-merge slices + meta + intelligence
fallbacks para campos no cubiertos por slices)
→ persist a {client_repo}/output/assembled-{period}.json (re-render-friendly)
Fase 3: CHECKPOINT OBLIGATORIO con el Lead (pre-generate — nunca saltarlo)
Fase 4: Generar HTML via generate-report.js CLI
→ CHECKPOINT pre-upload (local-only vs push)
Fase 5: (Opcional) Upload a pr-toolkit + git push + Vercel deploy
Fase 6: Output al Lead + update actividad.md
Fase 0: Context load
0.1 Validar inputs
const SLUG_RE = /^[a-z0-9][a-z0-9-]*$/;
const PERIOD_RE = /^\d{4}-\d{2}$/;
if (!SLUG_RE.test(slug)) → STOP: "slug invalido: {slug}. Debe matchear /^[a-z0-9][a-z0-9-]*$/"
if (!PERIOD_RE.test(period)) → STOP: "period invalido: {period}. Debe ser YYYY-MM"
Si el Lead no proveyo period, default al mes actual (YYYY-MM desde currentDate).
0.2 Leer contexto del cliente
Usando Read tool (absolute paths):
~/Documents/punto-rojo-clients/{slug}/cliente-CLAUDE.md— S1 (dominio, lead, etapa), S3 (accesos), S5 (progreso skills).~/Documents/punto-rojo-clients/{slug}/actividad.md— ultimas sesiones del equipo.~/Documents/punto-rojo-clients/{slug}/intelligence/perfil.md— identidad, audiencia, tono.~/Documents/punto-rojo-clients/{slug}/intelligence/objetivos.md— KPIs, targets.~/Documents/punto-rojo-clients/{slug}/intelligence/productos-foco.md— productos priorizados.
Si falta alguno de los 3 obligatorios (perfil, objetivos, productos-foco):
warning al Lead, no abortar — los slices son la fuente primaria; los
intelligence files solo cubren campos auxiliares (access_requirements,
onboarding_checklist, next_steps).
Intelligence opcionales (leer si existen): competidores.md, estacionalidad.md,
contexto-historico.md.
0.3 Operador correcto
Ver shared/skill-execution-protocol.md §Regla 6. Operador = userEmail prefix
(ej: nico.m@puntorojo.com → "Nico"). NUNCA usar cliente-CLAUDE.md.Lead como
nombre del operador — ese es el account manager del cliente.
Fase 1: Verify + validate slices
1.1 Required slices presentes
SECTIONS_DIR = ~/Documents/punto-rojo-clients/{slug}/sections/
REQUIRED = ['foda', 'tech-audit', 'history', 'ai-audit',
'competitive', 'benchmarks', 'context', 'action-plan']
OPTIONAL = ['content-strategy'] // Phase 9 — alimenta sec-16 §11.3 Matriz (v3 2026-05-12)
// (F-07 review 2026-06: el DEV_BYPASS_FLAG '--no-action-plan' fue eliminado — nunca existió en código)
OPT_OUT_FLAG = '--no-content-strategy' // skip content-strategy aunque exista
Para cada nombre en REQUIRED:
test -f "$SECTIONS_DIR/{name}.json"
Si NO existe → STOP con mensaje:
❌ Slice {name}.json no existe en {SECTIONS_DIR}.
Run /seo-section-{name} first.
(Este orquestador no genera la data — solo compone los 8 slices Phase 8 que ya
debieron correrse antes para este cliente/periodo.)
Excepción dev-only para action-plan.json:
- Si existe → leer y validar (igual que las otras 7).
Las secciones sec-16/17/18/19 (Roadmap + Build/Scale/Evolve + KPIs target) van a degradar a placeholders en el HTML. NO USAR en run productivo — el HTML entregado al cliente quedará incompleto. Continuo igual? [S] continuar / [N] STOP - Si NO existe → STOP (mismo mensaje que las otras REQUIRED — action-plan no tiene bypass).
Opcional content-strategy.json (Phase 9 — alimenta sec-16 §11.3 Matriz Cluster × Etapa × Disciplinas, v3 2026-05-12):
- Si existe + Lead NO pasó
--no-content-strategy→ leer + validar + deep-merge (Fase 2) + cross-validator obligatorio (Fase 1.5) + sec-16 §11.3 renderiza con clusters reales. - Si existe + Lead pasó
--no-content-strategy→ IGNORAR el slice + §11.3 NO renderiza. Warn al Lead que el slice existe pero se omitió por flag. - Si NO existe + Lead NO pasó
--no-content-strategy→ §11.3 simplemente no renderiza (sec-16 mantiene P1-P4). Cero degradación visible. Nota al Lead en checkpoint 3 que el cliente aún no tiene content-strategy generado. - Si NO existe + Lead pasó
--no-content-strategy→ mismo que el caso anterior (flag confirma intencionalidad). Sin warn extra.
1.2 Freshness check (warn si >30 dias)
Para cada slice (incluido action-plan si existe):
# Edad del archivo en dias
file_age_days=$(( ( $(date +%s) - $(stat -c %Y "$SECTIONS_DIR/{name}.json") ) / 86400 ))
Si file_age_days > 30:
⚠️ Slice {name}.json tiene {N} dias (>30). La data puede estar desactualizada.
Recomendacion: corre /seo-section-{name} para refresh antes de generar el reporte.
Continuo igual? [S] continuar / [N] STOP / [R] re-correr esa seccion (te lo
indico — esta skill no la corre por vos)
NO bloquear si el Lead responde [S]. Documentar el warning en el output final
del Lead (Fase 6) — "Generado con slices stale: {list}".
1.3 Validate cada slice via su validator
Por cada slice presente, leer + parsear + validar contra
report-builder/lib/{name}-validator.js:
| Slice | Validator | Funcion exportada |
|---|---|---|
| foda | report-builder/lib/foda-validator.js |
validateFodaSlice |
| tech-audit | report-builder/lib/tech-audit-validator.js |
validateTechAuditSlice |
| history | report-builder/lib/history-validator.js |
validateHistorySlice |
| ai-audit | report-builder/lib/ai-audit-validator.js |
validateAiAuditSlice |
| competitive | report-builder/lib/competitive-validator.js |
validateCompetitiveSlice |
| benchmarks | report-builder/lib/benchmarks-validator.js |
validateBenchmarksSlice |
| context | report-builder/lib/context-validator.js |
validateContextSlice |
| action-plan | report-builder/lib/action-plan-validator.js |
validateActionPlanSlice |
| content-strategy (opt.) | report-builder/lib/content-strategy-validator.js |
validateContentStrategySlice |
Estrategia: invocar todos los validators en una sola pasada Bash:
cd "${CLAUDE_PLUGIN_ROOT}/report-builder" && node -e '
const fs = require("fs");
const path = require("path");
// 8 slices REQUIRED (action-plan incluido — sin bypass, F-07 review 2026-06).
const slices = ["foda", "tech-audit", "history", "ai-audit", "competitive", "benchmarks", "context", "action-plan"];
const SECTIONS = "/path/to/sections/";
const results = {};
for (const name of slices) {
const validator = require(`./lib/${name}-validator.js`);
const fnName = `validate${name.replace(/-./g, m => m[1].toUpperCase()).replace(/^./, m => m.toUpperCase())}Slice`;
const validate = validator[fnName];
const slice = JSON.parse(fs.readFileSync(path.join(SECTIONS, `${name}.json`), "utf8"));
results[name] = validate(slice);
}
process.stdout.write(JSON.stringify(results, null, 2));
'
Si cualquier slice falla validacion (valid === false) → STOP con el
contenido de errors[] para que el Lead pueda corregirlo (re-correr la skill
afectada).
NO intentar fixear el slice inline — el extractor de cada skill es el unico responsable de su shape.
1.4 Process-and-discard temprano
Despues de leer + validar cada slice, retener en contexto solo el slice
parseado (no el raw text). Patron 5 de shared/context-engineering.md. El
assembled JSON final se persiste al client repo (Fase 2.5) — no se retiene en
context.
1.5 Cross-slice consistency (action-plan ↔ content-strategy)
Si content-strategy slice existe + se va a consumir (Lead no pasó --no-content-strategy):
ejecutar el cross-validator (Q3 decision 2026-05-12, expandido v3 con 4 rules nuevas
2026-05-12) para detectar drift entre los highlights agregados de sec-16
(action-plan.roadmap[*].source_slice='content-strategy') y los items reales de
sec-16 §11.3 Matriz Cluster × Etapa × Disciplinas (content_items + link_items
del slice). Rules v3 adicionales: cluster_completeness, discipline_inconsistency,
stage_mismatch, anchor_mix_invariant_violation (ver design doc §6.2).
cd "${CLAUDE_PLUGIN_ROOT}/report-builder" && node -e '
const fs = require("fs");
const { validateActionPlanContentStrategyConsistency } = require("./lib/cross-slice-validator");
const ap = JSON.parse(fs.readFileSync("/path/sections/action-plan.json", "utf8"));
const cs = JSON.parse(fs.readFileSync("/path/sections/content-strategy.json", "utf8"));
const r = validateActionPlanContentStrategyConsistency(ap, cs);
process.stdout.write(JSON.stringify(r, null, 2));
'
Outputs { valid, errors[], warnings[], drift[] }:
drift[].severity='critical'(missing_finding_id, orphan_finding_id, missing_content_strategy_slice) → STOP con detalle del drift y opciones:❌ Drift detectado entre action-plan ↔ content-strategy: • Highlight "Pillar Despensa M1-M3" (sec-16) apunta a source_finding_id 'content_build_99' pero ese ID no existe en content-strategy slice. → Probable causa: update content-strategy MOVE/REMOVE no propagado a action-plan. Opciones: [R] Re-correr /seo-section-action-plan para regenerar highlights sincronizados [E] Editar manualmente action-plan.json para arreglar el source_finding_id [F] Forzar continuar (drift queda documentado en actividad.md + audit_meta.cross_validator_warnings[])drift[].severity='warning'(category_mismatch, malformed_id, out_of_range_index, unparseable_finding_id, empty_category) → reportar al Lead en Fase 3 (checkpoint pre-generate) pero NO bloquear. Documentar en actividad.md.valid: true+ drift vacío → continuar a Fase 2 sin warn.
NO intentar fixear inline — los slices son autoritativos. Solo orquestar la re-ejecución de la skill upstream que generó el drift.
Fase 2: Compose assembled JSON
2.1 Construir meta (no viene de ningun slice)
const meta = {
client_name, // de intelligence/perfil.md o cliente-CLAUDE.md
client_slug: slug,
site_url, // de cliente-CLAUDE.md S1 (dominio)
industry, // de intelligence/perfil.md (snake_case)
country, // de cliente-CLAUDE.md S1 (ISO 3166-1 alpha-2 lowercase, ej "mx")
segment, // de intelligence/perfil.md o derivado (industry_country, ej "retail_mx")
date: period + "-01",
lead, // operador (userEmail prefix — Fase 0.3)
period, // "YYYY-MM"
generator: {
toolkit_version: /* leer de package.json root del toolkit. NUNCA hardcodear. */
}
};
Toolkit version:
node -e 'console.log("v" + require("'"${CLAUDE_PLUGIN_ROOT}"'/package.json").version)'
2.2 Deep-merge slices
El assembled JSON es la union de todos los slices + meta + fallbacks de intelligence files. Mapping slice → top-level keys:
| Slice | Emite top-level keys |
|---|---|
foda.json |
scoring (overall, label, maturity_level, pillars, weights, foda, priorities, roadmap) |
tech-audit.json |
diagnostic.{tech_seo, content_coverage, authority, audit_date, degradation} |
history.json |
history (audit_date, ga4_traffic, ahrefs_visibility, market_trends, degradation) |
ai-audit.json |
ai_visibility (audit_date, platforms, citability, queries_with_ai, geo_roadmap, kpis) |
competitive.json |
competitive_enrichment + top_content_by_competitor + top_content_by_competitor_findings |
benchmarks.json |
scoring.pillar_breakdowns (merge dentro de scoring) + audit_meta + degradation |
context.json |
executive + project_data + context (objectives_table, scope_table, journey_stages, personas_table...) + audit_meta (merge con benchmarks audit_meta) |
action-plan.json (si existe) |
roadmap, access_requirements, onboarding_meetings, checklist_meetings, next_steps_summary y scoring.roadmap (merge dentro de scoring). Keys canónicos post-v3.59.1 — los legacy onboarding_checklist/next_steps ya NO los emite el slice |
content-strategy.json (opt.) |
content_strategy (top-level con calendar_build/scale/backlog × content/links) + merge en audit_meta (scope_budget.content/links + changelog + version + cross_section_status) |
Merge logic (NO usar lodash — hacerlo a mano):
const assembled = {
meta,
...techAuditSlice, // emite { diagnostic }
...historySlice, // emite { history }
...aiAuditSlice, // emite { ai_visibility }
executive: contextSlice.executive,
project_data: contextSlice.project_data,
context: contextSlice.context,
competitive_enrichment: competitiveSlice.competitive_enrichment,
top_content_by_competitor: competitiveSlice.top_content_by_competitor,
top_content_by_competitor_findings: competitiveSlice.top_content_by_competitor_findings,
// foda + benchmarks ambos emiten `scoring` — merge: foda da overall/foda/priorities/roadmap/pillars/weights,
// benchmarks aporta pillar_breakdowns (sec-13)
scoring: { ...fodaSlice.scoring, pillar_breakdowns: benchmarksSlice.scoring.pillar_breakdowns },
// benchmarks + context ambos emiten `audit_meta` — context gana (mas campos), pero preservar
// industry_p50_pillars + coherence_check de benchmarks
audit_meta: {
...benchmarksSlice.audit_meta,
...contextSlice.audit_meta,
industry_p50_pillars: benchmarksSlice.audit_meta?.industry_p50_pillars,
coherence_check: benchmarksSlice.audit_meta?.coherence_check,
},
...(benchmarksSlice.degradation ? { degradation: benchmarksSlice.degradation } : {}),
};
2.3 Action-plan slice
⚠️ Fix F-06 (review 2026-06): esta sección documentaba un compose manual con los keys LEGACY pre-v3.59.1 (
onboarding_checklist/next_steps) que el slice 8/8 ya no emite — un Lead que lo siguiera al pie de la letra producía sec-17/18 vacías. El compose manual queda eliminado del flow: la Fase 2 entera delega en el script canónico, que es la única implementación mantenida:node scripts/compose-assembled.cjs {slug} {period} [--strict] [--no-content-strategy]El script carga los 8 slices requeridos (+ content-strategy opcional), valida cada uno con su validator, hace el merge canónico (keys post-v3.59.1:
onboarding_meetings,checklist_meetings,next_steps_summary), re-derivascope_budgety escribeoutput/assembled-{period}.json. Si necesitás entender el mapping slice→assembled, la fuente de verdad esscripts/compose-assembled.cjs(NO pseudocódigo en este doc — ya generó drift una vez).
Para referencia: el slice action-plan aporta roadmap (sec-16), access_requirements
(sec-17), onboarding_meetings + checklist_meetings (sec-18), next_steps_summary
(sec-19) y scoring.roadmap (merge dentro de scoring).
Nota --no-action-plan: este flag aparecía documentado como "DEV-ONLY bypass" pero
no existe en ningún código — compose-assembled.cjs trata action-plan como REQUIRED
(exit 1 si falta). Si falta el slice, correr /seo-section-action-plan antes de componer.
2.3.b Content-strategy slice (opcional Phase 9 — alimenta sec-16 §11.3 Matriz)
⚠️ STOP GATE ANTI-OMISIÓN (I14): antes de Phase 2.4, confirmar explícitamente una rama. Enforcement programático (F-08 review 2026-06): además de este gate procedimental,
generate-report.jsahora chequea al render: sisections/content-strategy.jsonexiste y el assembled NO traecontent_strategy→ block (exit 1 bajo strict default) salvo opt-out explícito--no-content-strategy(existe en generate-report.js Y compose-assembled.cjs, y deja degradation entry auditable). El caso Pomelo ya no puede pasar silenciosamente.
- [A]
content-strategy.jsonEXISTE + no se pasó--no-content-strategy→assembled.content_strategyDEBE quedar asignado. Si se omite el merge, §11.3 renderiza VACÍA en silencio (sin error —clusterMatrixdevuelve[]→ if-gate no renderiza → Lead no ve la matriz).- [B] slice no existe O flag activo → continuar; §11.3 no renderiza (por diseño).
OBLIGATORIO. No saltarlo aunque el Lead diga "continuar" o el modo sea Auto.
Si content-strategy.json existe + parsea OK + Lead NO pasó --no-content-strategy:
// v3 redesign 2026-05-12: el slice alimenta sec-16 §11.3 Matriz Cluster × Etapa
// × Disciplinas (template usa filter `clusterMatrix` de lib/sec16-matrix-builder.js
// para digerir content_strategy + roadmap por cluster temático).
assembled.content_strategy = contentStrategySlice.content_strategy;
// I14 — log explícito rama A para que el merge quede narrado y auditable.
console.log('[build-report] content_strategy merged — §11.3 matriz con', (contentStrategySlice.content_strategy?.calendar_build?.length || 0), 'build items');
// audit_meta merge: content-strategy aporta scope_budget.content + scope_budget.links
// + scope_constraints (v3: contract_months + stages_breakdown) + changelog +
// cross_section_status. NO pisa los campos de benchmarks/context — usa Object.assign
// defensivo.
//
// v3.46 — IMPORTANTE: re-derive scope_budget at compose-time (NO usar cs_meta.scope_budget
// directamente). Razón: slices generados con extractor antiguo tienen `links.*_allocated`
// en granularidad de PACKAGES en lugar de individual LINKS (1 link_item = 1 package mensual
// con N=links_count individuales — Q5 decision 2026-05-12). El bug de unidades reportaba
// utilización 13% para Chedraui (12 packages vs 96 link scope) cuando real era 100%
// (12 × 8 = 96 links). El extractor v3.46 suma `links_count` correctamente. Re-derive aplica
// el fix a slices legacy sin necesidad de regenerar — backward-compat 100%.
if (contentStrategySlice.audit_meta) {
const cs_meta = contentStrategySlice.audit_meta;
const { deriveContentScopeBudget } = require("./lib/content-strategy-extractor");
const cs = contentStrategySlice.content_strategy || {};
const freshScopeBudget = deriveContentScopeBudget(
{ build: cs.calendar_build || [], scale: cs.calendar_scale || [], backlog: cs.calendar_backlog || [] },
{ build: cs.link_calendar_build || [], scale: cs.link_calendar_scale || [], backlog: cs.link_calendar_backlog || [] },
cs_meta.scope_constraints || {}
);
assembled.audit_meta = {
...assembled.audit_meta,
scope_budget: {
...(assembled.audit_meta?.scope_budget || {}),
...(freshScopeBudget || cs_meta.scope_budget || {}),
},
// scope_constraints v3 (contract_months + stages_breakdown) viene de content-strategy
scope_constraints: {
...(assembled.audit_meta?.scope_constraints || {}),
...(cs_meta.scope_constraints || {}),
},
// changelog vive solo en content-strategy — append-only audit trail del slice.
content_strategy_changelog: cs_meta.changelog,
content_strategy_version: cs_meta.version,
};
}
Si NO existe O Lead pasó --no-content-strategy → omitir el merge. El template
sec-16 §11.3 detecta data.content_strategy ausente (vía clusterMatrix filter
que devuelve [] cuando no hay slice) y simplemente no renderiza la matriz —
sec-16 sigue mostrando P1-P4 intactos. Cero degradación visible. El sidebar de
base.njk mantiene count Nubank fidelity 18 fijo (sec-20 standalone deprecada
en v3 — count dinámico 18↔19 ya no aplica).
2.4 Intelligence fallbacks (campos NO cubiertos por slices)
Si despues del merge algun campo critico esta vacio + viene de intelligence:
| Campo | Fuente fallback (si slice falta) |
|---|---|
meta.industry |
intelligence/perfil.md line industry: ... |
meta.country |
cliente-CLAUDE.md S1 |
meta.segment |
intelligence/perfil.md o industry + "_" + country |
meta.client_name |
intelligence/perfil.md o cliente-CLAUDE.md S1 |
meta.site_url |
cliente-CLAUDE.md S1 |
NUNCA inventar metricas o data SEO. Solo metadata (nombres, URLs, country code) puede venir de intelligence cuando los slices no la cubren.
Si ningun fallback resuelve un campo requerido por generate-report.js
(meta.client_name es el unico hard requirement), STOP con mensaje claro.
2.5 Escribir JSON al client repo (B11 fix v3.37.2)
El assembled JSON se persiste al client repo (no a tmp) para que el Lead pueda re-render con patches data-side sin re-correr el pipeline completo. Ejemplo de uso: inyectar SimilarWeb post-fetch, fixear insights manuales, agregar slices nuevos sin regenerar todo.
ASSEMBLED_JSON="$HOME/Documents/punto-rojo-clients/{slug}/output/assembled-{period}.json"
mkdir -p "$(dirname "$ASSEMBLED_JSON")"
Escribir el assembled JSON con Write tool a $ASSEMBLED_JSON.
Pre-v3.37.2 (legacy): el JSON se escribía a os.tmpdir() y se borraba en
Fase 6.3 — imposible re-render con patches sin re-correr /seo-build-report
completo. Bug B11 (post-prosegur-ar empirical 2026-05-05).
2.6 Enrichment automático — SimilarWeb + GA4 demographics + PSI/CWV + refdomains-history + PSI client mobile (v3.55.0)
Tras escribir assembled-{period}.json en 2.5, invocar los 6 scripts de
enrichment que llenan los campos data-side que NO produce ningún slice de
Phase 8 (traffic real, channel mix, demografía, CWV per competitor, velocity
de adquisicion refdomains, PSI mobile client CWV para sec 11, snapshot de
métricas clave).
Mapping script → sección que llena:
| Script | Sección | Env var requerida |
|---|---|---|
enrich-with-similarweb.cjs |
sec 07 traffic_real_vs_estimated, sec 08 channel_mix.organic_vs_paid, sec 09 demographics.client_geography |
SIMILARWEB_API_KEY |
enrich-with-ga4-demographics.cjs |
sec 09 demographics.{gender_table, age_table} |
GA4 OAuth (tokens.json autoritativo, fallback .env) |
enrich-with-psi-cwv.cjs |
sec 06 competitive_enrichment.benchmark_seo[].cwv (LCP/INP/CLS per competitor) |
GOOGLE_PSI_API_KEY (free tier 25k/día) |
enrich-with-refdomains-history.cjs (v3.55.0) |
sec 13 diagnostic.authority.rows (Velocidad de adquisicion 12m) |
reads output/refdomains-history-{period}.json pre-generado via Ahrefs Site Explorer history endpoint |
enrich-with-psi-client-cwv.cjs (v3.55.0) |
sec 11 diagnostic.tech_seo.cwv.rows[].mobile (LCP/INP/CLS/TTFB/FCP client mobile, CrUX field + Lighthouse lab) |
GOOGLE_PSI_API_KEY |
enrich-with-metrics-snapshot.cjs (v3.78.0, I36) |
audit_meta.snapshot — canonical snapshot of 5 key metrics (refdomains_current, refdomains_yoy_growth_pct, organic_traffic_current, organic_traffic_yoy_pct, dr_current) + normaliza display fields (executive.kpi_cards, history.ahrefs_visibility.analysis[0].summary). Corre ÚLTIMO, después de enrich-with-refdomains-history.cjs (reutiliza refdomains_history_patch.growth_12m_pct ya escrito por ese script). |
ninguna (lee assembled JSON directamente) |
Graceful degradation: las libs subyacentes (similarweb-fetcher.js línea 30-31, psi-fetcher.js línea 28-31) devuelven { error, data: null } sin throw cuando falta la API key. Los scripts iteran logging warnings + escriben el assembled con placeholders ('—', cwv_status: 'critical'). El pipeline padre nunca aborta por falta de cred.
Skip opt-out: si el Lead invocó con --no-enrich, saltar esta Fase entera (ver sección "Manejo de flags" más abajo).
Tiempo estimado: ~3-10 min total. PSI sequential ~30s × 7 dominios = ~3.5min. SimilarWeb 8 dominios × 3 endpoints = ~2-4min. GA4 demographics ~30s.
Bash invocation:
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-C:/Users/nicko/OneDrive/Escritorio/Proyectos/Punto-Rojo/punto-rojo-claude-toolkit}"
cd "$PLUGIN_ROOT/report-builder" && \
node scripts/enrich-with-similarweb.cjs "{slug}" "{period}" && \
node scripts/enrich-with-ga4-demographics.cjs "{slug}" "{period}" && \
node scripts/enrich-with-psi-cwv.cjs "{slug}" "{period}" && \
node scripts/enrich-with-refdomains-history.cjs "{slug}" "{period}" && \
node scripts/enrich-with-psi-client-cwv.cjs "{slug}" "{period}" && \
node scripts/enrich-with-metrics-snapshot.cjs "{slug}" "{period}"
El && short-circuits SOLO en errores reales (bug en wireup → exit 1). Falta
de API key NO produce exit 1 (graceful). Si un script sí sale 1, el siguiente
no corre — la skill captura el exit code y reporta al Lead via run summary.
Backups: los 3 scripts ya escriben {file}.bak.pre-{psi|sw|ga4-demo}-{timestamp} antes de patchear (ver enrich-with-psi-cwv.cjs:86-87,99-100). Cleanup periódico de .bak.pre-* files es manual — no bloqueante.
Post-2.6: el assembled JSON ahora contiene SW + GA4 demo + CWV reales. Fase 3 (checkpoint) muestra los counts actualizados al Lead.
Fase 3: Checkpoint pre-generate
Presentar al Lead:
Voy a generar el reporte HTML para {client_name} del periodo {period}.
Slices Phase 8 cargados:
✓ foda.json ({age} dias, {N} priorities)
✓ tech-audit.json ({age} dias, audit_date {ISO})
✓ history.json ({age} dias, {N} meses serie)
✓ ai-audit.json ({age} dias, score citability {X}/10)
✓ competitive.json ({age} dias, {N} competidores)
✓ benchmarks.json ({age} dias, 3 pillars × {scores})
✓ context.json ({age} dias, {N} personas, {N} stages journey)
{✓|✗} action-plan.json ({age} dias o "missing — REQUIRED, correr /seo-section-action-plan")
Stale slices (>30 dias): {list o "ninguno"}
Data assembled:
overall_score: {X}/100
maturity_level: {Y}
pillar_breakdowns: 3/3
intelligence loaded: {Z/3 obligatorios + opcionales}
Salida HTML: ~/Documents/punto-rojo-clients/{slug}/output/{slug}-diagnostico-{period}.html
Salida JSON: ~/Documents/punto-rojo-clients/{slug}/output/assembled-{period}.json (persistente — re-render-friendly)
¿Arrancamos la generacion?
[S] Si, generar HTML
[N] No, ajustar algo
[R] Revisar el JSON assembled primero
Esperar respuesta explicita. Si [R], hacer Read del $ASSEMBLED_JSON y
mostrar al Lead antes de repetir el checkpoint.
Fase 4: Generar HTML
4.1 Invocar el CLI
Via Bash tool:
cd "${CLAUDE_PLUGIN_ROOT:-C:/Users/nicko/OneDrive/Escritorio/Proyectos/Punto-Rojo/punto-rojo-claude-toolkit}/report-builder" && \
node generate-report.js \
--diagnostic-json "$ASSEMBLED_JSON" \
--client "{slug}" \
--period "{period}" \
--json-summary
El CLI (B6 fix v3.37.2):
- Escribe el HTML a
~/Documents/punto-rojo-clients/{slug}/output/{slug}-diagnostico-{period}.html(resolve automático con--client+--period, default--client-repo-baseapunta al repo cliente persistente — ya NO escribe al install path del plugin). - Override con
--output <path>para destinos custom (debe vivir dentro dereport-builder/o del client repo base — path traversal rejected). - Emite mensaje humano a stderr (
✅ Report generated: ...). - Con
--json-summary, emite un single-line JSON a stdout con{ok, output, size_kb, sections, duration_ms, ...}.
4.2 Parsear resultado
- Exit code 0 + stdout JSON con
ok: true→ extraeroutput,size_kb,sections,duration_msy continuar a Fase 5. - Exit code != 0 o
ok: false→ reportar al Lead:
Si acepta: Read del❌ Generacion fallo: {error del stderr} El JSON assembled quedo en $ASSEMBLED_JSON para inspeccion + re-render con patches data-side. ¿Queres que inspeccione el JSON y re-intente? (S/N)$ASSEMBLED_JSON+ diagnosticar (puede ser un slice con shape mal validado por el orquestador). Si no: STOP con el JSON path documentado enactividad.md.
4.3 Validar output
Antes de Fase 5, verificar:
- El archivo existe en la ruta reportada (Bash
test -f). size_kb > 50(si el HTML es <50KB algo fallo — un reporte completo supera los 300-500 KB por CSS + JS inlined).sections >= 14(14 secciones IN minimo + algunas placeholder).
Si alguna validacion falla, reportar al Lead y ofrecer re-intentar.
4.4 Pre-render validators (v3.72.0 — Sprint 2 I26+I28+I33)
A partir de v3.72.0 el CLI generate-report.js corre automaticamente 3
validators sobre la baseline JSON ANTES de aplicar el SR overlay + render:
- cross-section-coherence (I33 + I34): detecta templating anti-patterns (palabras consecutivas duplicadas, circular templates) + number drift cross-section vs slice evidence.
- editorial (I28 + I30 + I32): aplica las reglas de
report-builder/data/prohibited-phrases.json— jerga academica/SEO sin claridad (block), adjetivos cualitativos sin dato nearby (warn), typos es-LATAM (warn). - source-coherence (I26 + I25 partial): cuando
audit_meta.source_of_truthesta declarado (e.g. "Ahrefs Site Audit"), detecta mentions narrativas de fuentes mutuamente excluyentes (e.g. SF crawl).
Comportamiento default: strict — si encuentra al menos 1 finding con severity=block, exit 1 con mensaje claro indicando validator + path + match
- comandos standalone para diagnosticar. Warns + infos se emiten a stderr siempre (visibles pero no bloquean).
Escape hatches (solo para iteracion local / debugging):
--no-strict-validators: emite warning + continua con render--skip-validators: no corre validators (NO recomendado pre-cliente)- env var
PR_DIAGNOSTICO_NO_STRICT_VALIDATORS=1: equivalente al flag - env var
PR_DIAGNOSTICO_SKIP_VALIDATORS=1: skip total
Si el render falla por validators (exit 1):
- NO usar
--skip-validatorspara "saltarlos" — los findings reportan bugs reales (templating, jerga, contradicciones). - Corre el CLI standalone para investigar:
cd ${PLUGIN_ROOT}/report-builder node scripts/validate-cross-section-coherence.cjs "$ASSEMBLED_JSON" node scripts/validate-editorial.cjs "$ASSEMBLED_JSON" node scripts/validate-source-coherence.cjs "$ASSEMBLED_JSON" - Aplicar patches al
$ASSEMBLED_JSON(rewriting narratives, fix templating, declararaudit_meta.source_of_trutho cambiarlo a"mixed-with-disclaimer"). - Re-correr
generate-report.jssin--skip-validators.
Por que pre-render y no post-render: si el HTML ya esta renderizado con templating bug ("Sitemap sitemap") o jerga ("techo competitivo"), el ciclo de fix es generar + revisar + patch + regenerate. El validator pre-render elimina ese loop — encuentras los bugs ANTES del render. Caso real: Pomelo Phase 6 (3-agents review) detecto 30+ residuales que el sweep regex no detecto; pre-render validators los hubieran detectado en 1 corrida.
Fase 4.5: Revisión pre-upload (gate de calidad editorial/coherencia)
Tras renderizar el HTML (Fase 4) y ANTES de subirlo (Fase 5), corré el gate de juicio
/seo-pre-upload-review. Complementa los validators determinísticos de §4.4 (aquéllos son
estructurales pre-render; éste es holístico post-render): 3 reviewers independientes (SEO senior,
Editor, Coherence) leen el HTML renderizado buscando lo que el determinismo no puede — completitud
del roadmap, sustento de claims, coherencia estratégica end-to-end, claridad C-level. Precedente: los
30+ residuales que el 3-agents review manual cazó en Pomelo (engram #1317).
4.5.1 Invocar el gate
/seo-pre-upload-review {slug} {period}
El skill resuelve el HTML + $ASSEMBLED_JSON por convención, corre los reviewers (subagentes paralelos
por default, inline fallback engram #1073), consolida por consenso (3/3 critical · 2/3 high · 1/3 sug) y
muestra el gate al Lead.
4.5.2 Checkpoint al Lead
El gate es soft con override — surface-a, no prohíbe:
¿Qué hacés con los findings del pre-upload review?
[A] Aplicar todo · [C] Solo críticos + high · [P] Ver plan de patches · [O] Override (subir igual)
Esperar respuesta. Si el Lead elige aplicar, los fixes van al assembled.json + re-render vía
apply-patches.cjs (volvés a tener HTML fresco). Auto Mode NO autoriza skip del gate cliente-facing.
4.5.3 Escape hatch (DEV-ONLY)
--skip-pre-upload-review (o PR_DIAGNOSTICO_SKIP_PRE_UPLOAD_REVIEW=1) salta el gate. NO recomendado
pre-cliente — solo para iteración de desarrollo.
Fase 5: Upload a pr-toolkit (opcional)
v3.65.0 (F12 — Lead feedback 2026-05-19): el flujo de upload fue extraído a scripts/upload-to-pr-toolkit.cjs (single source of truth). El skill sigue mostrando los CHECKPOINTS al Lead (L/U + S/N gates) pero la EJECUCIÓN delega al script. Más fácil de mantener + testear + reusable desde otros contextos (CI, batch).
5.1 Checkpoint al Lead
✅ HTML generado: {output_path} ({size_kb} KB, {sections} sections, {duration_ms}ms)
Opciones de distribucion:
[L] Local only — lo dejas local, lo mandas por email/drive al cliente manualmente
[U] Upload a pr-toolkit — commit + push, Vercel auto-deploya en ~60s a
https://pr-toolkit.puntorojo.com/reports/{slug}/{period}
(auth-gated @puntorojo.com, para equipo interno)
¿Que elegis? (L / U)
Si [L] local-only → saltar a Fase 6 directamente con el local path.
5.2 Upload via script wrapper (si [U])
El script report-builder/scripts/upload-to-pr-toolkit.cjs hace todo el trabajo:
preflight (path + git repo + working tree limpio + branch) → copy HTML → commit local. NO pushea por default — el push espera el checkpoint del Lead en 5.5.
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(pwd)}"
PR_TOOLKIT_PATH="${PR_TOOLKIT_PATH:-C:/Users/nicko/OneDrive/Escritorio/Proyectos/Punto-Rojo/pr-toolkit}" \
node "$PLUGIN_ROOT/report-builder/scripts/upload-to-pr-toolkit.cjs" \
"{slug}" "{period}" "{output_path}"
Exit codes del script:
0→ preflight + copy + commit OK. Continuar a 5.5 checkpoint.1→ preflight failed (path inválido / no git repo / args inválidos). STOP al Lead con el mensaje del script.2→ copy/commit failed. STOP al Lead — el script imprime instrucción de fix.3→ push failed (solo si se llamó con--auto-push). STOP — commit ya está hecho local, retry manual.
El script imprime JSON summary al stdout ({ok, slug, period, branch, commit_message, expected_url}). Capturar y mostrar al Lead.
5.5 CHECKPOINT pre-push (OBLIGATORIO)
NUNCA pushear sin aprobacion explicita. Presentar:
✅ Commit local creado en pr-toolkit ({PR_TOOLKIT_BRANCH}):
feat(reports): add {slug} diagnostic report {period}
Siguiente paso: `git push origin {PR_TOOLKIT_BRANCH}` → Vercel detecta + auto-deploya (~60s)
→ URL: https://pr-toolkit.puntorojo.com/reports/{slug}/{period}
¿Hago el push?
[S] Si, pushear ahora
[N] No, lo push-eo yo manualmente mas tarde
Esperar respuesta.
5.6 Push + Vercel deploy handoff
Si [S] → re-invocar el script wrapper con --auto-push (v3.65.0 F12):
PR_TOOLKIT_PATH="${PR_TOOLKIT_PATH:-C:/Users/nicko/OneDrive/Escritorio/Proyectos/Punto-Rojo/pr-toolkit}" \
node "$PLUGIN_ROOT/report-builder/scripts/upload-to-pr-toolkit.cjs" \
"{slug}" "{period}" "{output_path}" --auto-push
El script salta el commit (working tree ya tiene el commit de 5.2) y hace solo el git push. Si push exitoso (exit 0) → emite JSON summary con auto_pushed: true. Si push fallido (exit 3) → emite mensaje detallado de auth/non-fast-forward y deja el commit listo para retry manual.
Alternativa minimal (sin re-invocar script, solo push):
cd "$PR_TOOLKIT_PATH" && git push origin "$PR_TOOLKIT_BRANCH"
Error handling:
- Auth failure (
Permission denied,authentication failed) → reportar:❌ Push fallo por auth. Opciones: 1. Verificá `gh auth status` (GitHub CLI) 2. Verificá tu SSH key (`ssh -T git@github.com`) 3. Si son creds de Windows Credential Manager, re-logueate El commit local esta hecho — cuando resolvás, corré manualmente: cd {PR_TOOLKIT_PATH} && git push origin {PR_TOOLKIT_BRANCH} - Non-fast-forward → reportar que el remote cambio, sugerir
git pull --rebaseantes de reintentar.
Si el push exitoso → NO hacer sleep. Vercel desploya async en ~60-90s; en
vez de bloquear, handoff explícito al Lead con prompt interactivo:
✅ Push exitoso — Vercel auto-deploy en curso (~60-90s)
🔗 URL final: https://pr-toolkit.puntorojo.com/reports/{slug}/{period}
📊 Dashboard: https://vercel.com/puntorojo/pr-toolkit/deployments
Opciones:
[S] Ya validé la URL / seguí aunque no la haya abierto — Fase 6
[W] Esperá vos — reintento el check en ~60s (instrucción: me escribís "listo" cuando quieras avanzar)
[E] La URL no carga / devuelve error — pasame el síntoma y lo triageamos antes de Fase 6
Reglas de respuesta:
S→ avanzar a Fase 6 inmediatamente.Wo "listo" → avanzar a Fase 6 (el Lead ya esperó).E+ síntoma → NO avanzar a Fase 6. Triage: 404 por deploy todavía en progreso (esperar 60s más), 500 por file tracing fallido (revisarnext.config.ts > outputFileTracingIncludes), redirect loop por middleware (revisar matcher).
Fase 6: Output al Lead + update actividad.md
6.1 Reportar al Lead
✅ Reporte generado para {client_name}
🗂 Archivo local: {output_path} ({size_kb} KB, {sections} sections)
🔗 URL (auth-gated): https://pr-toolkit.puntorojo.com/reports/{slug}/{period} (si hizo upload)
📦 Slices Phase 8 usados:
• foda ({age}d) · tech-audit ({age}d) · history ({age}d)
• ai-audit ({age}d) · competitive ({age}d) · benchmarks ({age}d)
• context ({age}d) · action-plan ({age}d, REQUIRED — sin bypass)
⏱ Render: {duration_ms}ms
Stale slices (>30d): {list o "ninguno"}
**Share-ready**:
- Para clientes externos sin cuenta @puntorojo.com → mandá el archivo local por email/drive
- Para el equipo interno → pasá el URL hosted
**Tips antes de distribuir**:
1. Abrí el HTML local en Chrome y revisá el paginado
2. Validá que los nombres de Lead + equipo coincidan con el cliente actual
correr /seo-section-action-plan + re-disparar este skill SIN el flag para producción
4. PDF queda queued para un patch futuro
Skill completada. Escribi /context para ver cuanto espacio queda antes de continuar.
6.2 Update actividad.md
Usar Edit tool sobre ~/Documents/punto-rojo-clients/{slug}/actividad.md.
Agregar arriba del contenido existente (lo mas reciente primero):
## {YYYY-MM-DD} — {operador}
**Qué se hizo:**
- Generé reporte HTML del diagnóstico para período {period} usando 8 slices Phase 8
- {si upload:} Subí a pr-toolkit, URL: https://pr-toolkit.puntorojo.com/reports/{slug}/{period}
- {si local-only:} Dejé local en {output_path} — queda para compartir manual
**Decisiones tomadas:**
- Slices usados: foda, tech-audit, history, ai-audit, competitive, benchmarks, context, action-plan
- {si stale slices:} Slices stale (>30d): {list} — Lead aprobó continuar igual
**Pendiente:**
- Validar con cliente los hallazgos del reporte
- {si onboarding pending:} Cerrar items pendientes de onboarding
---
Mantener las ultimas 10 entradas — si hay mas, eliminar las mas antiguas.
6.3 Persistencia del assembled JSON (B11 fix v3.37.2)
El JSON assembled NO se borra al final del run. Vive persistente en
~/Documents/punto-rojo-clients/{slug}/output/assembled-{period}.json para
permitir re-render con patches data-side sin re-correr el pipeline completo.
Casos de uso típicos:
- Inyectar SimilarWeb post-fetch (handoff Prosegur AR pattern).
- Reescribir insights manuales (top channel detection, narrativa per-cliente).
- Agregar slices nuevos / cross-slice patches (ej. strip
<strong>literal). - Re-render rápido tras editar 1 sub-campo (vs ~85min de re-pipeline).
Para re-render con patches:
cd report-builder && \
node generate-report.js \
--diagnostic-json "$HOME/Documents/punto-rojo-clients/{slug}/output/assembled-{period}.json" \
--client {slug} \
--period {period}
No hay limpieza tmp — pre-v3.37.2 borraba os.tmpdir() JSON, comportamiento
deprecado por Bug B11 (post-prosegur-ar empirical 2026-05-05).
Manejo de flags
--no-action-plan — ELIMINADO (F-07 review 2026-06)
--no-action-planEste flag estaba documentado como "DEV-ONLY bypass" pero nunca existió en código:
compose-assembled.cjs trata action-plan como slice REQUIRED (exit 1 si falta).
Comportamiento real:
- Slice existe → flow normal (validate + merge action-plan).
- Slice missing → STOP
"Run /seo-section-action-plan first."(Fase 1.1) — sin bypass. - Para iterar en dev sin slice real: generar un stub con
/seo-section-action-plan --sample.
--no-content-strategy (opt-out apropiado para producción)
Skip explícito del slice content-strategy (Phase 9 — alimenta sec-16 §11.3 Matriz
Cluster × Etapa × Disciplinas, v3 redesign 2026-05-12). Este flag SÍ es válido en producción para
clientes cuyo scope contractual no incluye contenido/links, o cuando la skill
/seo-content-strategy aún no se corrió (cliente recién onboardeado).
Comportamiento:
- Sin la flag + slice existe → flow normal (validate + merge content-strategy + cross-validator) + §11.3 renderiza con clusters reales.
- Sin la flag + slice missing → §11.3 NO renderiza (sec-16 mantiene P1-P4 sin matriz). Cero degradación visible.
- Con la flag + slice existe → IGNORA el slice + §11.3 no renderiza + warn al Lead que el slice está disponible pero se omitió por flag.
- Con la flag + slice missing → §11.3 no renderiza sin warn extra (flag confirma intencionalidad).
Cross-validator corre SOLO cuando ambos slices están presentes y se consumen
(action-plan + content-strategy). v3 expansion: detecta cluster_completeness,
discipline_inconsistency, stage_mismatch, anchor_mix_invariant_violation
además de los 8 drift codes existentes (missing_finding_id, orphan_finding_id, etc.).
--no-enrich (opt-out apropiado para re-renders rápidos, v3.54.0)
Skip explícito de Fase 2.6 (enrichment SimilarWeb + GA4 demographics + PSI/CWV + refdomains-history + PSI client mobile + metrics-snapshot).
Casos de uso:
- Re-render rápido tras patch manual de insights — querés evitar regenerar la data SW/PSI ya consolidada en el
assembledprevio. - Iteración visual del HTML — no querés esperar ~3-10min de API calls.
- Debugging del render — Lead va a re-correr varias veces y no quiere burnear quota.
Comportamiento:
- Sin la flag (default) → Fase 2.6 corre los 6 scripts secuencial. Graceful skip por-script si API key falta.
- Con la flag → Fase 2.6 entera se saltea + warn
[seo-build-report] enrichment skipped via --no-enrich. El assembled queda como esté (presumiblemente ya enriquecido en un run previo, o degradado si nunca corrió enrichment).
NO afecta la skill /seo-diagnostico-full: ese flow invoca /seo-build-report SIN flag y siempre enriquece automáticamente. --no-enrich solo es para invocaciones standalone del Lead a /seo-build-report (re-renders).
--pdf
Si el Lead invoca con --pdf:
PDF export aún no está disponible en este release. El HTML está listo ahora y
te lo genero de todas formas. PDF queda queued para un patch futuro —
va a usar Playwright headless contra el HTML generado.
Mientras tanto, dos workarounds rápidos:
1. Abrir el HTML en Chrome → Ctrl+P → "Save as PDF"
2. Esperar el patch (sin ETA comprometido todavía)
¿Arranco con HTML ahora? (S/N)
Si [S] → continuar normalmente (Fase 0). Si [N] → STOP.
Error handling (resumen)
| Error | Fase | Accion |
|---|---|---|
| slug/period invalido | 0 | STOP con regex explicit |
| cliente-CLAUDE.md ausente | 0 | STOP — pedir setup del cliente |
| intelligence obligatorio faltante | 0 | Warning + continuar (los slices son la fuente primaria) |
| Required slice missing (incluye action-plan) | 1.1 | STOP — pedir correr /seo-section-{name} primero |
| action-plan missing | 1.1 | STOP — correr /seo-section-action-plan primero (sin bypass; F-07) |
| content-strategy missing (sin flag) | 1.1 | Warn ligero + continuar (§11.3 Matriz simplemente no renderiza — opcional Phase 9) |
content-strategy missing + --no-content-strategy |
1.1 | Continuar sin warn (flag confirma intencionalidad) |
| Stale slice (>30 dias) | 1.2 | Warn + ask Lead [S]/[N]/[R] |
| Slice falla validator | 1.3 | STOP con errors[] — no fixear inline, pedir re-run de la skill afectada |
| Cross-validator drift critical | 1.5 | STOP — opciones [R]e-run skill upstream / [E]ditar manual / [F]orzar continuar |
| Cross-validator drift warning | 1.5 | Reportar en checkpoint 3 + documentar en actividad.md, NO bloquear |
| meta.client_name no resoluble | 2.4 | STOP — el CLI requiere ese campo (exit code 2) |
| generate-report.js exit != 0 | 4 | Surface stderr + ofrecer inspeccionar $ASSEMBLED_JSON (persistente) |
| output <50KB o sections <14 | 4 | Warning + ofrecer re-intento |
| pr-toolkit path no existe | 5 | STOP con instrucciones (env var o clonar) |
| pr-toolkit no es git repo | 5 | STOP |
| working tree dirty | 5 | STOP — pedir commit/stash |
| git commit falla (hook) | 5 | Surface error, NO hacer --amend |
| git push auth failure | 5 | Instrucciones para resolver + commit queda local |
| Lead reporta URL 404 post-push | 5.6 | Esperar 60s mas (deploy en curso) o link a vercel.com/puntorojo/pr-toolkit/deployments |
| Lead reporta URL 500 post-push | 5.6 | Probable file tracing fallido — revisar next.config.ts > outputFileTracingIncludes |
| Lead reporta redirect loop post-push | 5.6 | Middleware matcher problema — revisar middleware.ts |
Reglas generales
- NUNCA inventes datos: si un slice no tiene un campo, propagar
{ available: false }o array vacio. Solo metadata (nombre, country, URL) puede venir de intelligence files cuando los slices no la cubren. - Checkpoints obligatorios (no auto-aprobables): Fase 3 (pre-generate) + Fase 5 (pre-push).
- Stateless: cada corrida lee los slices fresh desde disco, no cachea.
- Single-file output: el CLI inlinea CSS + JS — share-able por email sin romperse.
- Auth GSC/GA4: este skill no llama GSC/GA4. Si un slice trae
degradation.{gsc|ga4}conoauth_reauth_required, el reporte degrada esa seccion — el orquestador no redispara reauth. - PDF: queued para patch futuro. No prometer timelines.
MCPs utilizados + costos
Este orquestador es file system + 1 CLI call. Solo built-in tools:
- Read — cliente-CLAUDE, actividad, intelligence files, slices JSON.
- Bash —
test -f,stat, validator inline, mkdir, node CLI, git. - Write — assembled JSON persistente al client repo.
- Edit — actividad.md (prepend entry en Fase 6).
NO usar (toda esa data ya vive en los slices upstream): diagnostic-mcp,
memory-mcp, Ahrefs / GSC / GA4 / DataForSEO MCPs, Sheets, ClickUp.
Consumo APIs externas: $0 (0 Ahrefs units, 0 GSC/GA4 calls, 0 DataForSEO units).
El consumo real se pago al correr las 7-8 skills /seo-section-* previas. Re-ejecutar
este skill cuesta segundos + $0. Modelo Claude tampoco aplica (solo merge/render JSON +
templates Nunjucks, sin razonamiento).
Diferencia vs otros skills
Las 8 skills /seo-section-* (Phase 8) producen los slices. Este skill
los compone. /seo-reporte hace queries ad-hoc y resuelve findings — son
complementarios, no overlapping.
Flujo tipico:
/seo-section-foda → tech-audit → history → ai-audit → competitive → benchmarks
→ context [→ action-plan]
→ /seo-build-report → entregar al cliente
Contexto historico (Phase 8 split): pre-Phase 8 este skill consumia
consolidated_json del backend (diagnostic-mcp) + hacia enrichment Ahrefs
inline + reproducia logica de /seo-scoring. Ese diseño quedo deprecado: las
skills /seo-section-* pre-computan + persisten cada slice, y este orquestador
solo compone. La ventaja: re-ejecutar el reporte es $0 APIs externas + segundos,
y cada slice se puede regenerar/iterar independientemente.
Context window management
Patrones aplicados (shared/context-engineering.md): Patron 5 (process-and-discard
slices despues de leer cada uno) + Patron 6 (backend pre-computation: toda la
data pesada ya vive en los slices). Budget total: ~20-25 tool responses, sin
riesgo de compactacion.
References
- CLI:
report-builder/generate-report.js(entry point — input/output contract) - Sample shape:
report-builder/samples/chedraui-sample.json(estructura target del assembled JSON) - Slice samples:
report-builder/samples/sections/{foda,tech-audit,history,ai-audit,competitive,benchmarks,context}.json - Validators (cero deps, validan W3.4 contract):
report-builder/lib/foda-validator.js—validateFodaSlicereport-builder/lib/tech-audit-validator.js—validateTechAuditSlicereport-builder/lib/history-validator.js—validateHistorySlicereport-builder/lib/ai-audit-validator.js—validateAiAuditSlicereport-builder/lib/competitive-validator.js—validateCompetitiveSlicereport-builder/lib/benchmarks-validator.js—validateBenchmarksSlicereport-builder/lib/context-validator.js—validateContextSlicereport-builder/lib/action-plan-validator.js—validateActionPlanSlicereport-builder/lib/content-strategy-validator.js—validateContentStrategySlice(opt., Phase 9)
- Cross-slice validator (Sprint C Phase 9 — 2026-05-12):
report-builder/lib/cross-slice-validator.js—validateActionPlanContentStrategyConsistency(actionPlanSlice, contentStrategySlice)— detecta drift entre highlights agregados de sec-16 (source_slice='content-strategy') y items reales del slice content-strategy renderizados en §11.3 Matriz.report-builder/lib/sec16-matrix-builder.js—buildClusterMatrix(data)— registrado como filterclusterMatrixen generate-report.js. Digieredata.content_strategy.{calendar_*, link_calendar_*}+data.roadmap.*(concluster_temático) por cluster temático, ordena por priority_score desc, devuelve array de clusters con stages (build/scale/evolve) × disciplines (technical/content/linkbuilding) para que el template renderice §11.3.
- Schema W3.4:
docs/superpowers/specs/schemas/w3.4-diagnostic-data.schema.json - Content-strategy schema:
skills/seo-content-strategy/schema.json(Phase 9, strict W3.4) /seo-pre-upload-review(skill) — gate de juicio pre-upload (Fase 4.5): 3 reviewers independientes sobre el HTML renderizado. Spec: docs/superpowers/specs/2026-05-28-seo-pre-upload-review-design.md.- pr-toolkit repo:
C:\Users\nicko\OneDrive\Escritorio\Proyectos\Punto-Rojo\pr-toolkit\(Next.js app, Vercel auto-deploy) - Skills upstream (Phase 8):
skills/seo-section-{foda,tech-audit,history,ai-audit,competitive,benchmarks,context,action-plan}/ - Skill upstream (Phase 9, optional):
skills/seo-content-strategy/v3 — emite content_items + link_items v3 (drip distribution + anchor_mix + outreach_mix + cluster_concurrency_group) que alimentan sec-16 §11.3 Matriz Cluster × Etapa × Disciplinas (v3 redesign 2026-05-12, deprecó la sec-20 standalone)