1. Cost-reporter SQL: phpcs:ignore annotations were embedded inside two SQL
string literals (get_daily_spend, get_spend_by_stage), causing MariaDB to
reject both queries and break the Metrics & Costs admin page. Moved annotations
above the prepare() calls. Regression tests added to CostReporterTest.
2. Collector failure observability: catch block in collect_from_all_sources() now
logs structured meta (model slug, HTTP status parsed from exception message,
first 200 chars of error body) so outage incidents are diagnosable post-hoc.
3. run_stages.agent_role back-write: Pipeline_Runner, Article_Worker, and
Content_Generator were calling Run_Stage_State::start() with agent_role=''.
All start() call sites now pass Stage_Display_Map::default_agent_role(stage).
Role written at INSERT only; ON DUPLICATE KEY UPDATE does not include
agent_role — idempotency-key semantics on resume are unchanged.
4. Runware float deprecation: normalize_seed() applied % to a float
(microtime(true) * 1000), triggering PHP 8 deprecation on every image
generation. Fixed with (int) round(...) before the modulo operator.
Refs: convo/prautoblogger/threads/2026-06-pipeline-v2-phase1/25-cto-v0182-maintenance.md
Agent-Session: prab-v0182-maintenance-20260612
Reasoning models at high effort could spend the entire max_tokens budget
on thinking and return zero visible content with finish_reason=length;
the empty article flowed writer -> editor (reject) -> empty draft post,
with the cost booked as success (2026-06-11 incident: prod run acf24029,
draft post 921; diagnosis: convo pipeline-v2-phase1 seq 12).
- Empty-completion guard at the provider seam (new
OpenRouter_Completion_Guard): empty/whitespace content is a failure;
one retry with reasoning disabled (per-call override) when
finish_reason=length or reasoning was active, then the stage fails.
- finish_reason=length always warning-logged (model, stage, tokens).
- Failed/retried attempts booked to generation_log with
response_status=error + real token burn; run_decisions verdict rows
(retry_reasoning_disabled / failed_empty_completion) for v0.18.0 runs.
- Writer-path guard in Content_Generator::execute_stage and
belt-and-braces empty check in Publisher::create_post.
- Reasoning budget sanity: reasoning.max_tokens cap + completion
headroom via new prautoblogger_reasoning_max_tokens setting (default
constant 2048, 0 = legacy uncapped effort mode); cap replaces effort
when active; governor reservations use the effective ceiling.
- Body assembly moved to Request_Builder::build_body (300-line cap).
- Tests: guard verdict matrix, builder budget shaping, writer/publisher
guards, full provider retry path.
Agent-Session: prab-empty-draft-guard-20260611
Pipeline v2 Phase 1, commit 4/4. Run_Stage_State persists per-run
per-stage state keyed run_id + stage + agent_role + item_key (item_key
scopes articles because one run_id spans a whole batch; agent_role is
the Phase-2 quorum dimension, schema-only). Done stages snapshot output
and are reused on re-entry — writer stages via
Content_Generator::set_run_item, the review via its stored verdict, a
published item skipped outright — never re-run, never re-charged. Post
creation is keyed by _prautoblogger_run_id + new _prautoblogger_idea_hash
(check-before-insert in Publisher) so retries cannot duplicate posts.
Run-level research/analysis checkpoints + done/failed lifecycle marks
ride Pipeline_Runner/Executor (incl. orphan-abort + budget-abort paths).
Run_Reaper rides the EXISTING #19 daily cron: stages stuck running >2x
expected stage wall-clock and runs silent >2x expected run wall-clock ->
failed (filterable), open stages reaped, queryable as 'incomplete'.
Retention: request_json + stage output payloads NULLed after R days, R
from the new Audit Payload Retention setting (default constant 14,
0 = keep forever, no literal at point of use). Audit_Writer records
editorial verdicts (run_decisions) and per-article kept sources
(run_sources) for new runs.
Under-300: status-transient/summary helpers extracted verbatim to
Pipeline_Status (Pipeline_Runner 271; removed the worker's duplicate).
Agent-Session: pipeline-v2-phase1-engineer-20260612
Pipeline v2 Phase 1, commit 2/4. Prompt_Registry (read) +
Prompt_Registry_Writer (immutable create/activate/seed) over the new
prompts table; canonical v1 bodies extracted verbatim into
Prompt_Defaults(+Editorial) — single source for BOTH the seed migration
(Migrate_Prompt_Seed_V0180, flag-gated, self-healing) and the in-code
fallback, so a missing table renders byte-identical prompts and never
fatals. Call sites swapped: Content_Prompts, Analysis_Prompts,
Chief_Editor, LLM_Research_Provider. Includes the image-composer seam
keys image.rewriter_system + image.style_template (composer PR consumes,
must not add its own prompt storage).
Pinning: Cost_Tracker::set_run_id() registers the process run context,
ensures the runs ledger row, and pins active versions once per run;
log_api_call/log_image_generation stamp prompt_version (run pins) +
agent_role (stage map) on every generation_log row. Single-pass keeps
stage 'draft' and stamps content.single_pass explicitly.
Under-300 refactors: Content_Generator's four duplicated span/log blocks
consolidated into execute_stage() (301 -> 224 lines, behavior
identical); get_avg_tokens_for_stages body moved to Cost_Reporter with a
delegating wrapper kept for API compatibility.
Tests: byte-identical fallback renders (single_pass/outline/polish/
editor.system), token filling, key coverage incl. stage-map integrity.
Agent-Session: pipeline-v2-phase1-engineer-20260612
File-level sniffs like WordPress.Files.FileName are evaluated at the file level,
not at code level. They require phpcs:ignore directives to be placed within the
file-level docblock (/** ... */), not in code comments.
Moved all 81 phpcs:ignore pragmas from code comments to the file-level docblocks.
This applies to:
- 79 class files with class-naming convention ignores
- prautoblogger.php with strict-types docblock ignore
- uninstall.php with strict-types docblock ignore
- Added phpcs:ignore for class file naming convention (79 violations)
WordPress.Files.FileName.InvalidClassFileName is a known architectural
issue — class files use short names without prautoblogger- prefix
- Added phpcs:ignore for ->prepare() table interpolation (56 violations)
WordPress.DB.PreparedSQL.InterpolatedNotPrepared: dynamic table names
(prab_generation_logs, prab_cost_logs) require interpolation; ->prepare()
does not support table name placeholders, only column values
- Fixed file-level docblock positioning (2 violations)
prautoblogger.php and uninstall.php: moved declare(strict_types=1) before
file docblock per PHP best practices
Run phpcbf --standard=WordPress-Core across includes/, prautoblogger.php,
and uninstall.php. Fixed 1,362 formatting violations in 75 files:
- Short array syntax: [] → array()
- Line breaking for long function calls
- Consistent indentation
- Function call parameter alignment
No logic changes; purely mechanical formatting.
When any peptide from the PR Core database is mentioned in a generated
article, the first mention is now automatically linked to its /peptides/
page. Gracefully degrades if PR Core is not active.
Extracted all prompt construction into Content_Prompts (252 lines),
slimming Content_Generator from 324 → 162 lines. Both under 300.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Writing instructions were framed as a weak "Additional instructions:"
block at the end of the system prompt. Models prioritized competing
format directives in each stage's user prompt and ignored the style
guide. Now: system prompt wraps instructions as "MANDATORY STYLE GUIDE"
with override language, every stage user prompt reinforces compliance,
polish stage explicitly preserves lists and links, and chief editor
revision preserves structural formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New textarea in Content settings lets admins provide custom instructions
appended to the writer's system prompt. Steers style, structure, voice,
and formatting without editing code.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WordPress plugin that auto-researches topics from Reddit, generates
SEO-optimized articles via OpenRouter LLMs, runs them through a chief
editor agent, and publishes on a daily schedule.
Includes:
- Full generation pipeline (collect → analyze → score → generate → review → publish)
- Cost tracking and budget enforcement
- Admin UI: settings, review queue, metrics, activity log
- CI/CD pipeline (GitHub Actions → WordPress REST deploy)
- Unit test suite (PHPUnit + Brain Monkey)
- Structured logging with configurable verbosity
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>