Skip to content

Day 38 — Publish Through Gates

The original workflow deliberately writes the article before asking another model call to package it as metadata, HTML, and JSON-LD. Keep that separation. Packaging is a transformation that can lose content or create invalid markup.

Rankforge’s baseline validator requires recognizable sections:

let required: &[&str] = match stage {
Stage::Research => &["## Business summary", "## Search intents"],
Stage::Angle => &["## Primary keyword", "## Working title"],
Stage::Outline => &["# "],
Stage::Article => &["# ", "## FAQ"],
Stage::SeoPackage => &["## Meta", "## HTML", "## JSON-LD"],
};

This is syntactic validation only. It proves that a section marker exists, not that the angle is good, the FAQ answers real questions, the HTML is safe, or the structured data matches the visible article. Name the claim your validator actually establishes.

The TypeScript prompt forbids em dashes, en dashes, and semicolons. A prompt request is not enforcement. Rankforge scans the article and delivery package and rejects forbidden punctuation.

This small rule teaches a larger pattern:

deterministic requirement available? ─▶ enforce in code
semantic judgment required? ─▶ evaluate with evidence and calibrated review

Use code for one H1, required metadata fields, valid JSON parsing, safe HTML elements, URL syntax, and length bounds. Use evaluators or humans for usefulness, originality, tone, and whether an answer satisfies intent.

Prevent the packaging stage from thinning the article

Section titled “Prevent the packaging stage from thinning the article”

The baseline saves both blog-4-article.md and blog-5-seo-package.md. Add a coverage evaluator that extracts article headings and checks whether every accepted section appears in the HTML. Parse the JSON-LD fenced block into serde_json::Value and verify:

  • @type matches the visible content;
  • the headline matches the article H1;
  • FAQ questions and answers exist visibly in the HTML;
  • no unsupported rating, price, address, or date appears;
  • the canonical URL belongs to the configured site.

Do not publish JSON-LD simply because it parses.

Copy the fixture and make one mutation at a time:

  1. remove ## FAQ from the article;
  2. place a semicolon in its body;
  3. remove ## JSON-LD from the package;
  4. put valid JSON-LD under the wrong heading;
  5. add a supported section to Markdown but omit it from HTML.

Classify each failure as syntax, structure, semantic consistency, factual support, or editorial quality. Different failure layers need different repair behavior.

An article and its SEO package are now separate, inspectable artifacts with explicit acceptance rules. The model can draft and transform. Rust decides whether the delivery shape is complete enough to move forward.

Next: Day 39 — Cost Receipts and Tests →.