# Blog workflow efficiency (quality-preserving)

**Last Updated:** 2026-04-04  
**Purpose:** Faster iteration through **clear ladders** and **Make targets**—not fewer quality checks before publish.

## Principle

Efficiency here means less typing, fewer wrong files edited, and the **right** validator chain for the change. **Pre-publish** still means `make blog-post-validate-strict` when body, links, or competitive depth matter for that release.

## Body content (HTML) ladder

1. **Edit** canonical `docs/content/blog/posts/{category}/{slug}/content-draft.html` (or stdin/`/tmp` until ready). See [BLOG_CONTENT_EDIT_WORKFLOW.md](BLOG_CONTENT_EDIT_WORKFLOW.md).
2. **Optional:** `php v2/scripts/blog/update-post-content.php --post=SLUG --category=CAT --html=... --dry-run`
3. **Apply + validate (one step):**
   ```bash
   make blog-apply-validate POST=slug CAT=lexikon HTML=docs/content/blog/posts/lexikon/slug/content-draft.html
   ```
4. **Before publish / merge:** strict chain (compare WARN fails, internal links, content-flow, AEO diversity strict, **meta-intro audit** on the post’s JSON body):
   ```bash
   make blog-apply-validate-strict POST=slug CAT=lexikon HTML=docs/content/blog/posts/lexikon/slug/content-draft.html
   ```
   Equivalent: `./v2/scripts/blog/apply-and-validate-post.sh ... [--strict]`

5. **Validate only** (JSON already updated): `make blog-post-validate POST=… CAT=…` or `make blog-post-validate-strict POST=… CAT=…`  
   - `blog-post-validate-strict` ends with `make blog-audit-meta-intro` (meta-intro scan of **`v2/data/blog/posts/{CAT}/{POST}.json` body only**—ignores `content-draft.html` so WIP drafts do not fail publish checks). See [PEOPLE_FIRST_INTRO_AND_LINKING.md](PEOPLE_FIRST_INTRO_AND_LINKING.md).

6. **Meta-intro only (published body):** `make blog-audit-meta-intro POST=slug CAT=lexikon`.

7. **Meta-intro before apply (draft + JSON):** To scan `content-draft.html` / `content.html` as well as JSON, run:  
   `python3 v2/scripts/blog/audit-meta-intro-language.py --json-posts --post=slug --category=lexikon --fail-on high` (omit `--json-body-only`).

## FAQ-only ladder

Use when you **only** changed FAQs (e.g. `add-faqs-to-post.php` or pipeline `faq-answers-optimized.json` → post). If body, meta, or internal links changed in the same session, run **strict** body chain too.

1. Apply FAQs: `php v2/scripts/blog/add-faqs-to-post.php --post=SLUG --category=CAT [--replace]` (see [FAQ_SOURCE_OF_TRUTH.md](FAQ_SOURCE_OF_TRUTH.md)).
2. **FAQ-focused validation:**
   ```bash
   make blog-post-validate-faq POST=slug CAT=lexikon
   ```
   Runs: `validate-faq-quality.php`, `check-h2-faq-overlap.php`, `audit-faq-source-drift.php`.

3. **`audit-faq-source-drift.php`:** Exit `0` if OK or **SKIP** (no `faq-answers-optimized.json`). Exit `1` if published `faqs` and pipeline file **DRIFT**—fix or re-sync before publish.

4. If anything else changed: still run `make blog-post-validate-strict POST=… CAT=…`.

## Backup

For batch or high-risk JSON work, follow [.cursor/rules/blog-backup.mdc](../../.cursor/rules/blog-backup.mdc) and [guides/BACKUP_GUIDE.md](guides/BACKUP_GUIDE.md). Example: `python3 scripts/blog/backup-blog-content.py --manual` before large FAQ or content passes.

## Anti-patterns

- Skipping `blog-post-validate-strict` before publish “to save time” when the change affects body, depth, or links.
- Editing `v2/data/blog/posts/**/*.json` with search-replace (use scripts; see [blog-json-edit-prohibition.mdc](../../.cursor/rules/blog-json-edit-prohibition.mdc)).
- Treating `faq-research.json`, `faq-questions.json`, and post `faqs` as three parallel truths—see [FAQ_SOURCE_OF_TRUTH.md](FAQ_SOURCE_OF_TRUTH.md).

## Larger tooling (future)

Phase C options (Markdown/blocks/section CLI) live in [CONTENT_TOOLING_ROADMAP.md](CONTENT_TOOLING_ROADMAP.md)—not required for day-to-day HTML workflow.

## Related

- [CONTENT_SYSTEM_INDEX.md](CONTENT_SYSTEM_INDEX.md) — hub  
- [BLOG_SCRIPTS_USAGE_GUIDE.md](BLOG_SCRIPTS_USAGE_GUIDE.md) — script reference  
- [CI_BLOG_CONTENT_GUARDRAILS.md](CI_BLOG_CONTENT_GUARDRAILS.md) — why full per-post CI is not default on every PR
