name: zbeam-page-updater description: "Updates existing Z-Beam frontmatter pages with sourced data, FAQ replacements, and cleaningParameters. Requires category enricher package first."
Z-Beam Page Updater
Implementation scripts: skills/writing/zbeam-page-updater/references/updater-utils.py
Step 0a — Governance: prior knowledge check + hypothesis write
python3 skills/shared/check-prior-knowledge.py --slug [slug]
If USE_PRIOR or SUPPLEMENT: note prior findings and dead ends. If dead ends present, prefix hypothesis with "Prior dead ends — avoid: [deadEnds list]."
Infer hypothesis from enricher package fields being updated — never ask the user. Example: "Updating [slug] with [category enricher data — e.g. specific fluence thresholds for 6061-T6]. Hypothesis: adding [specific data type] will improve evalScore and dwell time for engineers comparing alloy options within 28 days."
python3 skills/shared/change-log-utils.py write \
--slug [slug] --skill zbeam-page-updater --mode update \
--hypothesis "[inferred — specific, testable, 28-day window]"
Step 0 — Prose constraints (read before writing any field)
Read skills/shared/writing-constraints.md. Apply all rules to every prose field you touch.
The structural validator checks these mechanically after writing — violations route back to revisor.
⛔ Pipeline gate — check before updating anything
python3 skills/writing/zbeam-page-updater/references/updater-utils.py gate_check [category] [subcategory]
# Exits 0 = OK, 1 = STALE (warn), 2 = BLOCKED (stop)
If BLOCKED: tell the user to run zbeam-category-enricher first.
Also check for an editorial brief (Mode B):
ls data/research/editorial-brief-[slug]-*-update.json
If missing, run zbeam-editorial-brief in Mode B before proceeding.
Intelligence freshness check
Use load_strategy_weights() from skills/shared/intelligence-utils.md. If age > 45, flag and continue. Apply weights when choosing which fields to prioritize.
Section mode — token-efficient per-section updates
When called with a section: argument, load only the data that section needs and run
only the steps listed for it. Skip the pipeline gate check for sections that don't
touch sourced numeric fields (faq, descriptions, serp).
| Section arg | Steps executed | Data loaded |
|---|---|---|
serp |
2-meta | Editorial brief sectionDirectives.serp only |
page |
2-pre page.description | Editorial brief + top Tier 1 finding |
characteristics |
2a (characteristics fields) + 2b-pre | Category package dataCardSources for characteristics |
laserInteraction |
2a (laserInteraction fields) + 2b-pre + 2d laserInteraction description | Category package dataCardSources + categoryTechnicalFindings |
machineSettings |
2b cleaningParameters + 2d machineSettings description | Category package dataCardSources fluence values |
industryApplications |
2d industryApplications description + 2d-post commercial handoff | Editorial brief sectionDirectives.industryApplications |
regulatoryStandards |
2e standards + 2d regulatoryStandards description | Category package applicableStandards + editorial brief |
faq |
2c FAQ replacement + FAQ keyword-stuffing check | Category package diverseFAQQuestions only |
descriptions |
2d all body heading descriptions | Category package categoryTechnicalFindings + editorial brief prose directives |
problems |
Write/update panels.problems.items[] — exactly 3 entries with title, description (≥40 words), bottomLine |
Editorial brief sectionDirectives.problems or derive from body content |
howToProceed |
Write/update howToProceed.title + howToProceed.steps[] — exactly 3 steps, last = Z-Beam CTA |
Editorial brief sectionDirectives.howToProceed or derive from machineSettings + commercial handoff |
Section mode workflow:
- Load only the data listed in the table above for the target section
- Execute only the listed steps
- Apply changes with surgical text replacement (never yaml.dump)
- Validate:
python3 -c "import yaml; yaml.safe_load(open('[path]'))" && echo valid - Report FAIL items and fix before signalling done
After all sections complete: run the content validator on the finished page.
You are applying targeted improvements to an existing frontmatter page. Every existing field is preserved unless it is being explicitly improved with sourced data. The output is a diff showing exactly what changed, for review before commit.
CRITICAL: Never use yaml.dump() for round-trip edits
yaml.dump() reformats the entire file — strips >- folded scalars, changes list indentation.
Always use surgical text replacement: Edit tool with exact string matching, or sed for single-line values. Validate after every write: python3 -c "import yaml; yaml.safe_load(open('[path]'))" && echo "valid"
Input required:
- Slug of the page to update (e.g.,
steel-laser-cleaning) - Category package:
data/research/category-data/[category]-[subcategory]-[date].json - Editorial brief (if available):
data/research/editorial-brief-[slug]-[date].json
Output:
- Updated YAML file written back to its original path
- Diff summary:
data/audit/page-update-[slug]-[date].md
Mandatory pre-write constraint read
Before writing or editing any prose field, read skills/shared/writing-constraints.md.
All three rules apply to every prose field you touch:
- Rule 1 — claim-first section opener
- Rule 2 — figure placement (never before the claim)
- Rule 3 — additive paragraphs must open with their own direct claim, not an authority attribution or conjunction
Do not skip this step on revision passes. The structural validator (Step 2s in the generation loop) checks all prose fields against these rules mechanically and routes failures back to you.
Plan
Print the fields to update with current vs. proposed values, then proceed immediately — no approval required.
Step 1: Load all inputs
Read the existing page via field projection first — do NOT cat the full YAML for
the planning phase. Only load the full file when you are about to write a patch.
python3 skills/writing/zbeam-page-updater/references/updater-utils.py context_read [slug] [content_type]
# Prints JSON dict of planning-phase fields
# Read the category package (most recent by date)
cat data/research/category-data/[category]-[subcategory]-[date].json
# Read editorial brief if it exists
cat data/research/editorial-brief-[slug]-[date].json 2>/dev/null
# Read the content auditor's remediation entry for this page
AUDIT=$(ls data/audit/content-audit-*.json 2>/dev/null | sort | tail -1)
[ -n "$AUDIT" ] && grep -A 10 '"slug": "[slug]"' "$AUDIT" 2>/dev/null
Before making any change, record the current state of every field you will touch (the "before" for the diff summary).
Step 2: Apply changes in this exact order
Read references/field-application-rules.md for the full field update protocol.
It covers: deprecated panel removal, section-mode routing, all field update steps
(dataCard, machineSettings, cleaningParameters, pageDescription, FAQ, SERP, crosslinks),
and section-specific prose rules.
Always apply in this order: deprecated removal → dataCard → machineSettings → cleaningParameters
→ pageDescription → FAQ replacement → SERP → crosslinks.
Never use yaml.dump() for round-trip edits — patch in place only.
Post-write self-check — run before YAML validation
python3 skills/writing/zbeam-page-updater/references/updater-utils.py post_write_check [saved_path] [content_type]
# Exits 0 = clean, exits 1 = hard FAIL items found (fix before committing)
Checks: ABBREVIATIONS expansion, BANNED_OPENERS, PARAGRAPH_STRUCTURE_RULE, PLAIN_LANGUAGE_RULE, page.description opener, application page.description length, citation URL integrity (Dim 5c), TOPIC_SENTENCE_RULE, FAQ keyword-stuffing, absent panels.problems / howToProceed.
Step 3: Validate
python3 -c "import yaml; yaml.safe_load(open('frontmatter/materials/[slug].yaml'))" && echo "YAML valid"
If invalid, revert to the backup made in Step 1 and report the error.
Step 4: Generate diff summary
Read references/diff-summary-template.md for the full markdown template. Save to data/audit/page-update-[slug]-[YYYY-MM-DD].md.
Also read references/content-quality-audit.md and run both advisory checks after Steps 2a–2e — flag issues but never pad content to meet them.
Step 5: Run cross-linker
After all updates are applied and validated, run zbeam-crosslinker on the updated page. Mandatory — cross-links connect the updated page into the semantic graph AI systems use to assess topical authority.
Step 6: Validate — run inline (mandatory)
After cross-linking, run zbeam-content-validator on the finished page:
- Read
skills/quality/zbeam-content-validator/SKILL.mdand invoke it now - PASS or CONDITIONAL PASS: report to user and mark complete
- FAIL: apply surgical fixes for each failing dimension, then re-validate
Do not mark the task complete until the report shows no blocking FAIL items.
What this skill does NOT do
- Does not rewrite the entire page — only touches specific fields
- Does change
pageTitleandmetaDescriptionwhen they fail CTR rules (Step 2-meta) - Does not rewrite
keywords— those require the full research → editorial → writer pipeline - Does not commit — produces the diff for review first
- Does not run if no category package exists — stop and tell the user to run
zbeam-category-enricherfirst
MANDATORY: Source fields must be real URLs
Every source: field written by this skill must contain a verified https:// URL.
ALLOWED: source: https://www.mdpi.com/1996-1944/14/9/2361
NOT ALLOWED: source: ai_research
NOT ALLOWED: source: scientific_literature
NOT ALLOWED: source: Huang et al., 2023
If no real URL is available: omit the source: field entirely.
Pre-write check — before writing any sourced value, call assert_source_url from updater-utils.py.
Post-write check — run after every file write:
python3 skills/writing/zbeam-page-updater/references/updater-utils.py check_source_urls [saved_path]
# Exits 1 on violations
The validator (Dim 5d) runs the same check and will FAIL any page with non-URL source values.
── Invocation (volatile — set once per run, referenced throughout) ──────────
# PROMPT-CACHE NOTE: All stable instructions above this section are cacheable.
slug = '[slug]' # ← fill at call time
category = '[category]' # ← e.g. "metal"
subcategory = '[subcategory]' # ← e.g. "ferrous"
content_type = 'material' # ← 'material' | 'application'
⏸ COMMIT GATE
Never auto-commit. Summarize what changed, provide the git command, wait for Todd to run it.