Two operator primitives, both queued (never synchronous — CPO hard
constraint), all mutations in the cron handler after re-validating
eligibility UNDER the generation lock:
- Replay (Stage_Replay + on_replay_job): one governed chat call from the
latest edited input fork. options_from_body() is the exact inverse of
build_body()+apply_reasoning_budget() (headroom subtracted back out;
reasoning pinned explicitly so global-setting drift can't reshape a
replay). Goes through send_chat_completion -> cost governor reserves
against the SAME run row (guardrail 4), retry/empty-guard machinery,
B1 recorder. Fresh output lands in the stage snapshot; downstream
stale-marked (guardrail 3); human_modified set at execution entry
(guardrail 2).
- Rebuild (on_rebuild_job): demote target+downstream to pending, re-enter
Article_Worker with the idea from the stored seed; upstream done stages
reuse (never re-charged), demoted stages rebuild prompts from CURRENT
snapshots — how an upstream edit propagates. Decisions recorded while
rebuilding a human-modified item are flagged.
- Rerun_Eligibility: published/future/private = frozen (guardrail 5,
server-side); executing runs blocked; editable stages = writer chat
stages (outline/draft/polish); chain-order downstream sets.
- Run_State::reopen(): atomic terminal->running gate, ceiling
re-snapshotted from the current setting, accumulated spend NEVER reset.
- Publisher: re-run output refreshes the existing UNPUBLISHED post
(status preserved — re-runs never publish); published posts untouched.
- Article_Worker persists the exact idea payload as a seed (INSERT-once)
so rebuilds can't mis-derive item_key and duplicate a post.
- Rerun_Job_Support: queue/lock/budget/status-transient plumbing; jobs
ride the M1 status transient so the board shows queued->pickup->result.
Agent-Session: engineer-prab-m3-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