Skip to content
Back to skills

New Blog

ASecurity

Use when: kullanıcı "yeni blog yaz", "blog üret", "content gen", "blog draft", "makale yaz", "yeni içerik üret", "new blog post", "pillar yaz", "cluster yaz" der ya da /pseo-new-blog çağırır; master.xlsx[new_content_plan] satırından plan al, SERP analiz yap, 5 template render et, JSON-LD @graph 5 entity üret, Foundational Principles 3-katman (truth-verifiable + profile-aware + anti-cheap-content) enforce et. Also use when: master.xlsx[topical_map] içinde assigned_url=null olan pillar/cluster/...

  • 27 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 2, 2026
ai-agentspythonrustgobashapidatabase

Works with

  • terminal
  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned October 2, 2026

npx -y skills add popiliadam/platinum-seo-engine --skill new-blog --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of New Blog?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for New Blog
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/popiliadam-new-blog/badge)](https://www.skillsdirectory.com/skills/popiliadam-new-blog)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: new-blog
description: |
  Use when: kullanıcı "yeni blog yaz", "blog üret", "content gen", "blog
  draft", "makale yaz", "yeni içerik üret", "new blog post", "pillar yaz",
  "cluster yaz" der ya da /pseo-new-blog çağırır; master.xlsx[new_content_plan]
  satırından plan al, SERP analiz yap, 5 template render et, JSON-LD @graph
  5 entity üret, Foundational Principles 3-katman (truth-verifiable +
  profile-aware + anti-cheap-content) enforce et.
  Also use when: master.xlsx[topical_map] içinde assigned_url=null olan
  pillar/cluster/supporting satırı için ilk içerik üretilecek; new_content_plan
  satırının lifecycle_status=GREEN ya da PLANNED durumda; mode='draft'
  (review) veya 'publish' (immediate) seçildi; profile-aware switch tetik
  (project-config[profile] ya da project-config[profiles] priority merge).
  Do not use when: mevcut blog revize için (revise-content kullan); FAQ
  block re-render için (faq-optimization kullan); decay/sunset/prune için
  (content-remediation kullan); image generation için (generate-images
  kullan); manuel WordPress upload için (Section A upload-instructions
  template render edilir, skill upload yapmaz); master.xlsx eksikse
  (init-project önce çalışmalı, DURUR #1).
version: "1.0"
status: wip
category: production
inputs:
  project_slug:        { type: string,  required: true,  description: "Workspace proje slug'ı (örn 'projeA'). projects/{slug}/ dizinine map edilir." }
  new_content_plan_id: { type: string,  required: true,  description: "master.xlsx[new_content_plan] row id reference (kolon A)." }
  mode:                { type: string,  required: false, default: "draft", description: "Output mode — 'draft' (review öncesi) veya 'publish' (immediate). Enum dışı değer DURUR #5." }
outputs:
  - "outputs/blog/{slug}/article.html"
  - "outputs/blog/{slug}/schema.jsonld"
  - "outputs/blog/{slug}/meta-tags.json"
  - "outputs/blog/{slug}/upload-instructions.md"
  - "_state/events.jsonl"
consumes:
  - "init-project:master.xlsx[new_content_plan]"
  - "init-project:master.xlsx[cluster_keywords]"
  - "init-project:master.xlsx[topical_map]"
  - "init-project:project-config[profile]"
  - "init-project:project-config[content_settings]"
  - "init-project:project-config[brand_identity]"
  - "rules/content-quality.md"
  - "rules/content-html-discipline.md"
  - "rules/content-seo-discipline.md"
  - "rules/content-eeat-discipline.md"
  - "rules/content-llm-discipline.md"
  - "rules/content-update-discipline.md"
  - "rules/content-craft-discipline.md"
  - "templates/content/new-blog.template.md"
  - "templates/content/new-blog.template.html"
  - "templates/content/faq-block.template.html"
  - "templates/content/upload-instructions.template.md"
  - "scripts/production/new_blog.py"
  - "scripts/production/quality_gates.py"
produces:
  - "content-remediation"
  - "faq-optimization"
  - "generate-images"
  - "indexing-ping"
triggers:
  manual: ["/pseo-new-blog"]
  natural_language: |
    "yeni blog yaz", "blog üret", "content gen", "blog draft",
    "makale yaz", "yeni içerik üret", "new blog post yaz",
    "pillar yaz", "cluster yaz", "supporting içerik yaz"
  hooks: []
  scheduled: []
mcp_tools:
  required:
    - "mcp__gsc__search_analytics"
    - "mcp__dataforseo__serp_organic_live_advanced"
    - "mcp__ScraplingServer__stealthy_fetch"
  optional:
    - "mcp__dataforseo__dataforseo_labs_google_keyword_overview"
budget:
  uses_paid_mcp: true
  estimated_credits: 8
autonomy:
  confidence: HIGH
  requires_approval: true
  safe_auto_execute: false
---

# new-blog — production skill (Phase 11 Wave 1, W-F1)

Plan-driven full-article generator. Reads a single
`master.xlsx[new_content_plan]` row, joins it against
`master.xlsx[cluster_keywords]` (keyword set + intent + forbidden filters)
and `master.xlsx[topical_map]` (pillar/cluster/supporting page_type +
internal-link plan), runs SERP top-10 + **mandatory** Tier-1 Scrapling
competitor recon (×10 organic, CCE arming) and gates the draft against the
Brief Paketi, then renders four artifacts:

1. `outputs/blog/{slug}/article.html` — `<article class="pse-blog-post">`
   fragment (R-22 fragment boundary; no `<html>` / `<body>` wrap).
2. `outputs/blog/{slug}/schema.jsonld` — JSON-LD `@graph` with 5
   entities (Article + Organization + Person + BreadcrumbList +
   FAQPage; R-78..R-83).
3. `outputs/blog/{slug}/meta-tags.json` — meta title (≤580px desktop)
   + meta description (≤990px desktop) per R-35 (single authority) +
   OpenGraph + Twitter card pack.
4. `outputs/blog/{slug}/upload-instructions.md` — Section A new-blog
   manuel WordPress upload workflow (R-74); skill itself does NOT
   publish.

The skill is **READ-ONLY** with respect to `master.xlsx`
(`new_content_plan` allowed_writers is `null` — F-1 schema authority,
verified pre-flight). It never calls `transaction.append`,
`transaction.update`, or `transaction.delete` against the workbook.
The only state mutation is the audit append to `_state/events.jsonl`
with `event_type=content_new`.

## Inputs (frontmatter contract)

| Name                  | Type   | Default | Notes                                                                         |
|-----------------------|--------|---------|-------------------------------------------------------------------------------|
| `project_slug`        | string | —       | Required. `projects/{slug}/` workspace root.                                  |
| `new_content_plan_id` | string | —       | Required. Row id (kolon A) in `master.xlsx[new_content_plan]`.                |
| `mode`                | string | `draft` | `draft` (review) or `publish` (immediate). Other values → DURUR #5.           |

## Outputs (artifacts produced)

- `outputs/blog/{slug}/article.html` — schema-markup-aware, WCAG 2.1 AA
  compliant, BEM `pse-` CSS class prefix HTML article fragment.
- `outputs/blog/{slug}/schema.jsonld` — JSON-LD `@graph` 5 entity
  (Article + Organization + Person + BreadcrumbList + FAQPage).
- `outputs/blog/{slug}/meta-tags.json` — meta title (≤580px) + meta
  description (≤990px) per R-35 + OG + Twitter pack.
- `outputs/blog/{slug}/upload-instructions.md` — Section A new-blog
  WordPress manual upload steps (R-74).
- `_state/events.jsonl` — audit append, `event_type=content_new`,
  `event_kind=work` (events.schema enum: provenance / work / audit /
  workflow), `schema_version=1.0`.

## Foundational Principles Enforcement (3-Layer)

The 3 üst-prensip (Phase 10 `rules/content-quality.md#foundational-principles`)
gate this skill end-to-end. No alt-rule (R-01..R-148) overrides them.

### Principle 1 — Truth-Verifiable Content (R-27, Süleyman 5x vurgu)

**Statement.** Tüm content/source/link/data %100 doğru ve kanıtlanabilir;
uydurma yasak (kaynak, hikaye, case study, fiyat, stat, ürün/feature/
image-link).

**3-katman defense (Step 8 implements):**
- Layer 1: skill prompt explicit "uydurma yasak" başlangıçta — Step 7
  generation öncesi system note inject.
- Layer 2: post-generate fact-check pass — her claim için
  `content_settings.original_research_database` + SERP top-10 source
  match; citation count ≥ R-44 threshold.
- Layer 3: citation enforce — R-44 source verification 3-katman + R-105
  expert quote bank-driven (`content_settings.experience_database`
  lookup, uydurma quote yasak).

**Failure mode:** RED — yayın iptal, çıktı discard. DURUR #6 trigger.

### Principle 2 — Profile-Aware Enforcement

**Statement.** Skill behavior `project.config.json[profile]` enum'una
göre değişir (singular field, Phase 11 W-F1 cascade fix). When `profile`
is unset, fall back to `profiles[]` priority merge per
`rules/content-quality.md` Principle 2 tablosu.

**Enum 5-value:** `e-commerce` / `ymyl` / `local-service` / `b2b-saas` /
`portfolio`.

**Switch logic (Step 2 + Step 7 + Step 8):**

| Boyut                      | YMYL                       | e-commerce        | b2b-saas          | local-service       | portfolio  |
|----------------------------|----------------------------|-------------------|-------------------|---------------------|------------|
| Author byline (R-28)       | Zorunlu                    | Yok               | Esnek             | Esnek               | Yok        |
| Tone                       | semi-pro + siz             | conversational+sen| formal + siz      | conversational+siz  | esnek      |
| Word count                 | 1500–4000                  | 800–2500          | 1800–3500         | 1000–2500           | 800–2000   |
| Counter-argument (R-50)    | Zorunlu                    | Skip              | Opsiyonel         | Skip                | Skip       |
| Disclaimer (R-51)          | medical/legal/financial    | Skip              | Opsiyonel         | Skip                | Skip       |
| Image style                | clean-illustration         | product-photo     | diagram-screenshot| location-photo      | esnek      |
| Stats density (R-104)      | min 1/500w, max 1/200w     | min 1/800w, max 1/300w | min 1/600w, max 1/250w | min 1/1000w, max esnek | esnek |

**Failure mode:** AMBER — wrong profile resolution worker raporlar; RED
ancak `profile` enum dışı (DURUR #2).

### Principle 3 — AI Suistimal Önlemi (Anti-Cheap-Content, 7-pattern gate)

**Statement.** AI'ın doğal cheap content padding davranışını preempt et.

**7-pattern gate (Step 8 implements):**
- H3 zorunluluk gate — H2 word count > 200 → min 2 H3 (R-30).
- Heading keyword density %40–60 — primary_keyword count / total heading
  count (hard cap, R-30 stuffing önleme).
- Citation density per 500 word 1-2 (R-106).
- FAQ count talep-güdümlü 3-6 (kanıt varsa), hard cap 10 (R-09).
- Stats density profile-aware min/max (R-104 **tek kaynak / single
  source**; yukarıdaki tablo R-104'ün min+max cap'lerini birebir taşır,
  new-blog kendi sayısını uydurmaz — FIX-H5 hizalaması).
- Per-H2 list cap 1 (R-07; multi-list AI padding önleme).
- AI signature humanize — `brand_identity.tone_phrases_blocklist`
  consume + replace pattern ("Aslında", "Sonuç olarak", "Özetle",
  R-118).

**Failure mode:** AMBER warning (auto-correct attempt) → RED fail
(manuel revise). 2x AMBER aynı pass → RED upgrade.

## R-121 Bank Selection Logic (Pre-Publish)

Bank entry (R-105 expert quote / R-114 original research / R-119
first-hand experience) selection passes a **3-step filter** before any
template renders. Step 7 (`render_5_templates`) reads the result; Step
12 (`emit_provenance`) records the chosen entries. R-121 catches
**semantic** repetition (the same core fact copy-pasted across many
blogs); R-118 catches **stylistic** repetition (AI signature words
within one page). The two rules compose — both fire pre-publish.

1. **Topic match.** `entry.applicable_topics ∩
   (new_content_plan.primary_keyword ∪ new_content_plan.assigned_cluster
   ∪ topical_map[matching_row].cluster) ≠ ∅` → entry remains a
   candidate; empty intersection → entry skipped.
2. **Profile density cap.** From the candidate set, select up to the
   per-profile maximum:
   - YMYL: 2 experience + 1 research entry per content
   - b2b-saas: 1 experience + 1 research entry per content
   - e-commerce / local-service / portfolio: 1 experience + 0 research
     entry per content
3. **Rotation (30-day).** For each remaining candidate, count usage in
   the append-only `_state/events.jsonl` `content_new` work events whose
   `note` records `bank_entry_id == entry.id` AND
   `timestamp >= now - 30d`. Skip if
   `count >= entry.max_usage_per_month`; rotate to a different entry or
   to a different `phrasings[]` form of the same entry.

If all candidates fail the 3-step filter, the skill emits AMBER and
retries with `phrasings[]` rotation; 2x AMBER same pass → RED upgrade
(manual review).

**Post-publish usage record** (in the `events.jsonl` audit append at
Step 12): the `content_new` work event records the `bank_entry_id`(s)
used inside its `note` field — the append-only `_state/events.jsonl` is
the **only** state surface this skill writes (consistent with the
READ-ONLY claim above). The rotation counter at Step 3 reads from this
same append-only `content_new` event log on the next invocation —
single source of truth. The skill does **NOT** write
`master.xlsx[completed_work]` (`allowed_writers=null` — F-1); if a
durable `completed_work` row is later required, the done-protocol /
mark-done skill owns that append.

**Schema enablement (v1.4, commit `8e07e1c`):** each bank entry exposes
`applicable_topics`, `phrasings`, `last_used_in_content_id`,
`max_usage_per_month`. Stage C of brand-onboarding (commit `cb8df43`)
populates these via R-44 evidence-gated atomic write.

**Runtime integration deferred to Phase 11 Wave 2.** This SKILL.md
section is the spec lock. `scripts/production/new_blog.py` now exists (CCE
B4 orchestrator helpers `assemble_brief` / `evaluate`) but does NOT yet
implement the R-121 3-step bank filter. When Wave 2 lands that runtime,
the 3-step filter implements as a pre-`render_5_templates` helper consumed
by Step 7.

## R-124 — YMYL Uzman İnceleme İmzası (Pre-Publish Expert-Review Sign-Off)

YMYL profillerinde (`profile == "ymyl"`), R-124 gereği yazar künyesi
(R-28) yalnızca **kayıtlı bir insan incelemesi** ile geçerlidir. Bu
skill, YMYL içeriğini yayınlamadan ÖNCE zorunlu bir inceleme-imzası
adımı çalıştırır (Step 11.5 `ymyl_review_signoff`, Step 11 ile Step 12
arasında):

1. **Operatör inceleyiciyi adlandırır.** Yayın öncesi, operatör (Süleyman
   ya da atanmış uzman) insan **reviewer** (inceleyenin) adını verir.
   Reviewer adı yoksa → **DURUR #9** (RED, yayın bloklu — R-124).
2. **Audit kaydı (events.jsonl, append-only).** Skill, inceleme kanıtını
   `scripts/state/events_writer.append_audit(...)` ile bir
   `event_kind=audit` satırına yazar:
   - `audit_action="modified"` (events.schema 6-değer canonical enum
     `{created, modified, deleted, accessed, permission_changed,
     config_changed}` — içeriğin yayın-öncesi inceleme kapısı
     onaylandı/değiştirildi).
   - `audit_target="content:{project_slug}:{post-slug}"`.
   - `actor="skill:new-blog"`.
   - `notes` payload üç zorunlu alan taşır (R-124): **reviewer**
     (inceleyen adı) + **review_date** (ISO 8601) + **content_version**
     (content hash veya R-103 revision id).
3. **Eşleştirme.** Bu audit satırı, R-28 künyesinin arkasındaki gerçek
   insan inceleme kanıtıdır (Principle 1 Truth-Verifiable + EEAT
   Trustworthiness). İnceleme kaydı olmadan adlı yazar künyesi =
   uydurulmuş yazarlık sinyali (Google rater-guideline "Lowest"). R-28
   künyeyi görünür kılar; R-124 künyenin arkasında belgelenmiş bir insan
   inceleme olmasını zorunlu kılar.

Non-YMYL profillerde bu adım atlanır (R-28 künye opsiyonel/yok), audit
satırı yazılmaz.

## CCE Döngüsü (Competitive Content Engine — Silahlan → Yaz → Kapı → Re-write)

new-blog artık CCE motorunu çalıştırır: rakipten **ölçülebilir biçimde daha
iyi** içerik üretmek için bir **silahlan → yaz → kapı → re-write** döngüsü.
Mimari kural (spec §3): döngüyü **Claude (bu skill) sürer** çünkü
`scripts/production/new_blog.py` SAF Python'dur — MCP'yi/Claude'u ÇAĞIRMAZ;
döngüye yalnızca iki saf yardımcı verir (`assemble_brief`, `evaluate`). MCP
sınırı skill'e (Claude'a) aittir; deterministik tutkal koda.

### 1. Silahlan (Arming) — ham MCP JSON → Brief Paketi

Claude ham veriyi MCP ile toplar (kod değil), diske yazar, sonra
`new_blog.assemble_brief(...)`'i çağırır:

| Sinyal              | MCP tool (Claude çağırır)                                          | Not                                  |
|---------------------|-------------------------------------------------------------------|--------------------------------------|
| SERP top-10 organic | `mcp__dataforseo__serp_organic_live_advanced` depth=10            | rakip sıralaması + URL listesi       |
| Rakip DOM ×10       | `mcp__ScraplingServer__stealthy_fetch`                            | **ZORUNLU** her organic URL (Step 4) |
| Keyword genişleme   | `mcp__dataforseo__dataforseo_labs_google_keyword_suggestions` + `…_keyword_overview` | reliable substring + volume/intent   |
| AI Overview         | `serp_organic_live_advanced` `ai_overview` bloğu                  | gerçek `answer_points` (Step 5)      |
| GSC sinyali         | `mcp__gsc__search_analytics`                                      | `{real_queries, current_position}`   |

`assemble_brief` 3 B1 transform'u sırayla çalıştırır (`competitor_recon_transform`
+ `keyword_aio_intel_transform` + `build_brief`) → tam **Brief Paketi**
(`gap` + `structure_ceiling` + `keyword_set` + `aio` + `gsc`). GSC sinyali
`gsc=` parametresiyle `build_brief`'in boş default'unu override eder.

### 2. Yaz (Craft) — Claude, R-149+ rehberiyle

Claude makaleyi yazar; `rules/content-craft-discipline.md` (R-149..R-153)
**pozitif yazım katmanını** uygular: pain-mirror empati girişi (R-149), somut
örnek/senaryo (R-150), aktif marka sesi (R-151), rakip-üstü özgün değer
`data-original="true"` (R-152), H2 derinliği + mantıksal akış (R-153). Brief'in
`gap` maddeleri kapsanır; `structure_ceiling`+1 anlamlı tablo/liste hedeflenir.
Foundational Principles 3-katman + R-121 bank seçimi yine geçerlidir (üstte).

### 3. Kapı (Gate) — `new_blog.evaluate(...)`

Üretilen HTML `new_blog.evaluate(content_html, brief, round_num=..., max_rounds=3)`
ile ölçülür; bu `scripts/production/quality_gates.py`'nin `run_all`'ini **IMPORT
ile** çağırır (subprocess değil) — 8 kapı sırasıyla: p0_truthfulness > gap >
structure > depth > aeo > voice > originality > schema_visual. Döner:
`{gate_result, action, feedback}`.

### 4. Re-write / Terminal — döngü kararı

| `action`         | Anlam                       | Sonraki adım                                                       |
|------------------|-----------------------------|-------------------------------------------------------------------|
| `PASS`           | overall PASS                | yayın akışına devam (Step 9+)                                     |
| `REWRITE`        | overall RED, round < 3      | `feedback` (= `rewrite_feedback`) ile YENİDEN yaz (adım 2)        |
| `AMBER_TERMINAL` | overall RED, round ≥ 3       | **3-tur cap** — sonsuz döngü YOK; eksik kapılar operatöre raporlanır (spec §8) |

`AMBER` yalnız orkestratör kararıdır; kapıların kendisi PASS/RED kalır. Döngü
`PASS`'e ya da `AMBER_TERMINAL`'e ulaşana kadar adım 2 ↔ 3 tekrar eder. Craft
kuralı ↔ kapı eşlemesi: R-149 → voice+aeo, R-150 → depth, R-151 → voice,
R-152 → originality, R-153 → depth (`content-craft-discipline.md`).

## Routing — 12-Step Workflow

> Step names are stable identifiers across runs (used as
> `steps[*].name` when the skill calls `workflow_runner.create_run`).

### Step 1 — `read_master_xlsx`

`master.xlsx[new_content_plan]` row read where
`id == {input.new_content_plan_id}`. `master.xlsx[cluster_keywords]`
filter where `assigned_url == new_content_plan.url_slug`.
`master.xlsx[topical_map]` filter where
`pillar == new_content_plan.assigned_cluster` OR
`cluster == new_content_plan.assigned_cluster`.

Workbook opens with `openpyxl.load_workbook(read_only=True)`. F-1
allowed_writers=null discipline: skill MUST NOT call
`transaction.append`, `transaction.update`, or `transaction.delete`.

`new_content_plan` 14 columns consumed:
`id, title, url_slug, primary_keyword, monthly_volume, assigned_cluster,
target_word_count, priority, created_date, tivl_tag, lifecycle_status,
image_prompt, alt_text, content_type` (Phase 10 additive bump).
`content_type` enum: `[listicle, guide, comparison, research, tutorial,
review]`.

`cluster_keywords` 11 columns consumed: `cluster, keyword,
monthly_volume, data_source, assigned_url, gsc_clicks, gsc_impressions,
gsc_position, intent, forbidden_kw, forbidden_reason`. `intent` enum:
`[Informational, Commercial, Transactional, Navigational]`.

`topical_map` 10 columns consumed: `pillar, cluster, primary_keyword,
monthly_volume, data_source, assigned_url, page_type, status, priority,
note`. `page_type` enum: `[pillar, cluster, supporting]`.

**DURUR #1.** master.xlsx eksik → init-project skill önce çalışmalı.

### Step 2 — `read_project_config` (Profile-Aware Switch)

`projects/{slug}/project.config.json` parse. Singular `profile` field
(schema v1.2, Phase 11 W-F1 cascade fix) is the dominant Principle 2
switch; when missing, fall back to `profiles[]` priority merge per
`rules/content-quality.md` Principle 2 tablo.

`content_settings` 14 fields consumed (Phase 10): `toc_strategy,
related_posts_strategy, author_strategy, css_strategy, indexnow_enabled,
ai_training_optin, video_integration, internal_data_sharing,
external_uniqueness_check, original_research_database,
experience_database, video_database, disclaimer_templates, image_model`.

`brand_identity` 18 fields consumed (Phase 10): `logo_url, primary_color,
secondary_color, accent_color, font_family_heading, font_family_body,
header_template_id, footer_template_id, source_url_for_sampling, tone,
hitap, anglicism_tolerance, tone_phrases_blocklist, font_heading,
font_body, default_hero_url, same_as_urls, image_style`.

**DURUR #2.** Singular `profile` enum dışı bir değere sahipse RED;
schema v1.2 cascade fix uygulanmadıysa (`schema_version != "1.2"` ve
profile field schema'da yok) önce `scripts/migrations/0002_project_
config_1.1_to_1.2.py` çalışmalı.

### Step 3 — `serp_analysis` (R-08)

`mcp__dataforseo__serp_organic_live_advanced` çağrı:
`keyword=new_content_plan.primary_keyword`, `depth=10`. Top-10 sonuç +
entity extract (organic results `dom_url`, `title`, `description`).

**DURUR #5.** SERP analiz fail (boş response, API error, mode enum dışı)
→ manuel input gerekli, skill `awaiting_approval`.

### Step 4 — `scrapling_competitor_recon` (CCE silahlanma, R-08 derinleştirme)

**ZORUNLU (artık optional değil; top-3 değil top-10).** SERP top-10 organic
sonucun HER BİRİ için `mcp__ScraplingServer__stealthy_fetch` ile DOM çekilir —
CCE silahlanma motoru rakip kapsamasının TAMAMINI görmeli (spec §4a), yarısını
değil. Her sayfa `{"url": ..., "html": ...}` olarak biriktirilir; bu liste +
ham SERP `assemble_brief`'e verilir → `competitor_recon_transform` heading tree
+ answered questions + candidate entities + structure ceiling (anlamlı
tablo/liste) + word_count çıkarır.

Tier-0 fallback (basic SERP description) yalnızca tek bir URL kalıcı 403/blok
verirse o URL'e özgüdür; Scrapling **required** MCP bağımlılığı olduğundan
adım topluca atlanamaz. Eksik/bloklu sayfalar AMBER warning raporlanır,
silahlanma toplanan sayfalarla devam eder.

### Step 5 — `aio_citation_check` (R-109/R-110/R-111 + CCE AEO)

Pasaj alıntılanabilirlik: SERP top-10 page'lerde featured snippet detect
(R-109), people_also_ask (R-110), ai_overview citation (R-111).

**CCE AEO bağı.** Ham `serp_organic_live_advanced` payload'undaki `ai_overview`
bloğu boş heuristik DEĞİL, `assemble_brief` → `keyword_aio_intel_transform` ile
gerçek `aio.answer_points` (+ `aio.cited_sources`) listesine dönüştürülür ve
Brief Paketi'nin `aio` alanına yazılır. Bu `answer_points` B2 kapı motorunun
**aeo** kapısı tarafından ölçülür: içerik bu noktaların HER BİRİNİ kapsamalı
(`aio.present=False` ise yalnız "intro cevap-önce" şartı — R-149 / spec §6 R2).

### Step 6 — `content_gap`

`cluster_keywords[forbidden_kw]` negatif filter (forbidden_reason
kontrol). `topical_map` gap detect: `status == 'planned' AND
assigned_url == null`. Internal link plan: relevant
`topical_map[pillar/cluster]` URL'leri article body içinde reference
(per ~300 word 1 link, R-06).

### Step 7 — `render_5_templates`

5 template render-time slot consume (4 file + 1 internal upload section):

1. `templates/content/new-blog.template.md` — markdown skeleton
   (frontmatter + H1/H2/H3 outline). Planning-only, NOT yayınlanır.
2. `templates/content/new-blog.template.html` — HTML article fragment
   (`<article class="pse-blog-post">` kök, R-22 fragment boundary).
3. `templates/content/faq-block.template.html` — FAQ statik R-43
   (accordion `<details>` + `<summary>` YASAK, R-43 statik HTML zorunlu).
4. `templates/content/upload-instructions.template.md` — Section A
   new-blog kısmı.

Render-time slot dictionary:

| Slot                 | Source                                                           |
|----------------------|------------------------------------------------------------------|
| `{primary_keyword}`  | `new_content_plan.primary_keyword`                               |
| `{tone}`             | `brand_identity.tone` (Principle 2 profile-aware override)       |
| `{hitap}`            | `brand_identity.hitap`                                           |
| `{primary_color}`    | `brand_identity.primary_color`                                   |
| `{font_heading}`     | `brand_identity.font_heading` (alias to font_family_heading)     |
| `{font_body}`        | `brand_identity.font_body`                                       |
| `{author}`           | `content_settings.author_strategy` switch (YMYL byline-required) |
| `{disclaimer}`       | `content_settings.disclaimer_templates[profile_kind]`            |
| `{default_hero_url}` | `brand_identity.default_hero_url` (R-77 fallback)                |
| `{image_style}`      | `brand_identity.image_style` (Principle 2 profile-aware)         |

CSS class prefix: `pse-` BEM (plugin agnostik — proje slug
hardcode YASAK, e.g. `demo-dental`/`demo-furniture`/`demo-hvac`/`demo-petcare`/`demo-shop`/
`demo-tires`/`demo-construction`/`demo-agency` slug'lar HTML/CSS içinde geçemez).

### Step 8 — `foundational_principles_gate`

3-katman gate çalışır (Principle 1 + 2 + 3 yukarıda detaylı). Çıktı:
P1 RED → DURUR #6; P2 enum dışı → DURUR #2; P3 7-pattern AMBER 2x →
RED upgrade.

### Step 9 — `render_jsonld_graph` (R-78..R-83)

JSON-LD `@graph` 5 entity render:

- `Article` — `headline, description, datePublished, dateModified,
  author (Person ref), publisher (Organization ref), image, mainEntityOfPage`.
- `Organization` — `name, logo (logo_url), sameAs (same_as_urls;
  R-100)`.
- `Person` — `name, jobTitle, knowsAbout` (`author_strategy` switch,
  R-105 expert quote bank-driven `content_settings.experience_database`
  lookup; uydurma yasak — Principle 1 Layer 3).
- `BreadcrumbList` — Home > Pillar > Cluster > Article (R-83 4-level
  cap).
- `FAQPage` — talep-güdümlü 3-6 FAQ Q&A items, hard cap 10 (R-79; R-09).

Validate: Google Rich Results Test API mock validate (skill internal —
actual API call optional). DURUR #8 trigger: REJECT → schema fix önce.

### Step 10 — `meta_pixel_wcag_validate`

Meta title pixel calc: ≤580px desktop (R-35 single authority; ~60 char
is only a tech-audit approximation heuristic — Türkçe glyph widths
vary, so the pixel cap is authoritative, not the char count). Meta
description pixel calc: ≤990px desktop (R-35; ~160 char heuristic
only). DURUR #7 trigger: cap aşımı → auto-correct attempt; fail ise
manuel revise.

WCAG 2.1 AA axe-core simulate: violations=0 hedef. Color contrast
(`primary_color` vs background) ≥ 4.5:1. Image alt text required
(`new_content_plan.alt_text` consume; uydurma alt-text yasak —
Principle 1).

### Step 11 — `write_outputs`

4 artefact yaz:

- `outputs/blog/{slug}/article.html` — `<article class="pse-blog-post">`
  kök, R-22 fragment boundary.
- `outputs/blog/{slug}/schema.jsonld` — JSON-LD `@graph`.
- `outputs/blog/{slug}/meta-tags.json` — meta title/description/OG/
  Twitter pack.
- `outputs/blog/{slug}/upload-instructions.md` — Section A WordPress
  media library workflow (R-74).

### Step 12 — `emit_provenance`

`_state/events.jsonl` append (audit):

| Field            | Value                                          |
|------------------|------------------------------------------------|
| `event_type`     | `content_new`  (events.schema event_type enum) |
| `event_kind`     | `work`         (events.schema enum, ADR-020)   |
| `schema_version` | `1.0`                                          |
| `actor`          | `skill:new-blog`                               |
| `target`         | `master.xlsx[new_content_plan]#{id}`           |
| `timestamp`      | UTC ISO 8601                                   |
| `mode`           | `input.mode` (`draft` / `publish`)             |

## DURUR Conditions (9)

| #  | Trigger                                               | Resolution                                           |
|----|-------------------------------------------------------|------------------------------------------------------|
| 1  | master.xlsx eksik                                     | init-project önce çalışmalı (Phase 5 W-Q paterni)    |
| 2  | project-config[profile] enum dışı / schema v1.2 yok    | scripts/migrations/0002_project_config_1.1_to_1.2.py |
| 3  | 6 rules dosyası eksik                                 | Phase 10 deliverable verify (e4369ea commit)         |
| 4  | MCP budget aşımı (estimated_credits 8)                 | scripts/budget/check_budget.py blocked               |
| 5  | SERP analiz fail (R-08, mode enum dışı)               | manuel input, awaiting_approval                      |
| 6  | P1 fact-check fail                                    | RED — çıktı discard, claim revize                    |
| 7  | meta pixel cap aşımı                                  | auto-correct fail ise manuel revise                  |
| 8  | Schema Rich Results Test REJECT                       | JSON-LD `@graph` fix önce                            |
| 9  | YMYL profili + reviewer adı yok (R-124 imza eksik)    | RED yayın bloklu; operatör reviewer adlandır + append_audit kaydı (reviewer+review_date+content_version) |

## Cascade Fix W-F1 (Phase 10 EKSİĞİ Closure — Atomic Commit Içinde)

Phase 10 finished without `project-config[profile]` (singular) which
Foundational Principle 2 directly cites. Phase 11 W-F1 closes that gap
in the SAME atomic commit as the new-blog skill itself, so this skill
ships with a schema-valid Principle 2 contract from day one.

**File 1 — `schemas/project-config.schema.json`:**
- `schema_version` `"1.1"` → `"1.2"`.
- `properties.profile` added (singular, enum 5-value:
  `e-commerce` / `ymyl` / `local-service` / `b2b-saas` / `portfolio`).
- `required[]` UNCHANGED (additive policy →
  `rules/schema-versioning-discipline.md`).

**File 2 — `scripts/migrations/0002_project_config_1.1_to_1.2.py`:**
- 0001 paterni reuse (idempotent + dry-run + `.bak` backup).
- Refuses out-of-range source versions; pure `migrate(doc) -> dict`
  function for tests.

**File 3 — `scripts/state/bootstrap_project.py`:**
- `SCHEMA_VERSION = "1.1"` → `"1.2"` constant update.

**File 4 — `tests/skills/test_init_project.py`:**
- `schema_version` assertion `"1.1"` → `"1.2"`.
- Asserts schema declares `profile` field with the exact enum 5-value.

**Smoke test (cascade fix verify):**

```bash
python3 scripts/migrations/0002_project_config_1.1_to_1.2.py \
    --in /tmp/test_config.json --dry-run
jq '.properties.schema_version.const' schemas/project-config.schema.json
jq '.properties.profile.enum'         schemas/project-config.schema.json
```

Expected: schema_version `"1.2"`, profile.enum array of 5 strings.

## Plugin-Agnostic Discipline

- No project slug hardcoded inside this skill or its templates
  (`demo-dental`, `demo-furniture`, `demo-hvac`, `demo-petcare`, `demo-shop`, `demo-tires`,
  `demo-construction`, `demo-agency` are FORBIDDEN tokens — pytest grep verifies).
- CSS class prefix `pse-` BEM only (`pse-blog-post`, `pse-h2-answer`,
  `pse-tldr`, `pse-faq-block`).
- Brand styling resolves at render-time from `brand_identity` (per-
  project), never via hardcoded color/font.
- Per-call / per-url credit shape names (Phase 7 lesson, ADR-028 anti-
  pattern) MUST NOT appear in this skill — `budget.estimated_credits`
  (number) is the only allowed shape per skill-frontmatter schema.

## Error Handling

| Failure                          | Mode  | Action                                                                |
|----------------------------------|-------|-----------------------------------------------------------------------|
| master.xlsx schema drift         | RED   | DURUR #1, init-project re-run                                         |
| project-config[profile] dışı     | RED   | DURUR #2, cascade fix verify                                          |
| MCP DataForSEO budget exhausted  | RED   | DURUR #4, budget gate                                                 |
| Tier-1 Scrapling 403 / blocked   | AMBER | tier-0 SERP description fallback                                      |
| P1 citation missing              | RED   | DURUR #6, claim revize                                                |
| P3 7-pattern AMBER 2x same pass  | RED   | manuel revise                                                         |
| meta pixel cap > 580 / 990 (R-35)| AMBER | auto-correct → fail RED                                               |
| Schema Rich Results REJECT       | RED   | DURUR #8, `@graph` fix                                                |

## References

- `rules/content-quality.md` (Foundational Principles, R-01..R-148).
- `rules/content-html-discipline.md` (R-22 fragment, R-23 inline CSS,
  R-43 statik FAQ, R-77 fallback hero).
- `rules/content-seo-discipline.md` (R-08 SERP, R-78..R-83 schema).
- `rules/content-eeat-discipline.md` (R-28 byline, R-44 source verify,
  R-104 stats-density single-source, R-105 expert quote, R-114/R-119
  research bank, R-124 YMYL pre-publish review sign-off).
- `rules/content-llm-discipline.md` (R-109..R-111 AIO citation, R-118
  humanize).
- `rules/content-update-discipline.md` (R-50 counter-argument).
- `rules/content-craft-discipline.md` (R-149..R-153 — CCE pozitif yazım
  katmanı: pain-mirror giriş, somut örnek, marka sesi, özgünlük, derinlik).
- `scripts/production/new_blog.py` (CCE B4 orkestratör yardımcıları —
  `assemble_brief` + `evaluate`; saf Python, MCP/Claude çağırmaz).
- `scripts/production/quality_gates.py` (CCE B2 8-kapı motoru — `run_all`).
- `schemas/project-config.schema.json` v1.4 (Phase 3.1 bank entry
  schema bump — `applicable_topics`, `phrasings`,
  `last_used_in_content_id`, `max_usage_per_month` fields R-121 reads;
  W-F1 v1.2 + Phase 11 cascade still applies for `profile` singular).
- `schemas/master-excel.schema.json` (18 sheets — `internal_links` and
  `content_gaps` are NOT among them; F-4 schema authority).
- `schemas/events.schema.json` (event_type enum 12 values, event_kind
  enum 4 values).
- `schemas/skill-frontmatter.schema.json` (8 required fields, category
  enum 8 values, status enum 3 values).
- ADR-020 (event_kind=workflow vs work routing).

## Wave-Out Note

This skill is `status: wip` until Phase 11 Wave 2 acceptance gate;
`active` bump deferred to the post-Wave 1 closeout. Manager owns the
status flip + governance audit.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.