The test test_gd_rung_emits_passthrough_featured_and_single_warning forced
the capability to 'gd' via the filter override, causing the orchestrator to
instantiate PRAutoBlogger_Image_Composer_Editor and call compose_variants().
Inside cover_crop(), get_temp_dir() was the first WP function called —
unstubbed, Brain Monkey 2.x threw LogicException on all three PHP versions.
Add the three stubs that ImageComposerEditorTest already uses for the same
code path (same house pattern):
- get_temp_dir → sys_get_temp_dir() . '/'
- wp_get_image_editor → WP_Error (no GD editor in test env)
- is_wp_error → isinstance alias
With wp_get_image_editor returning WP_Error, cover_crop() returns null for
every role → compose_variants() returns [] → the GD rung emits
array_merge($passthrough, []) = only the pass-through featured.
The existing assertions (assertNotEmpty, assertSame 'featured', assertSame
'raw_base_bytes') all fire against a real execution path and cannot pass
trivially — this is the actual degradation-to-passthrough contract.
Assertions are not weakened.
Agent-Session: engineer-prab-maint-fix-20260612
Items completed:
1. GD-rung tests (QA P2, verdict 2026-06-11-6f76df1.md P2-1):
- New ImageComposerEditorTest.php: 7 tests covering wp_get_image_editor WP_Error,
resize WP_Error, upscale size-mismatch guard, save WP_Error, zero-width geometry
guard, missing-role guard, and successful OG resize happy path.
- Orchestrator gd-rung test added to ImageComposerTest.php: forces capability='gd'
via filter, asserts Imagick renderer is never called, pass-through featured is
always first.
2. Dead layout keys removed (QA P3, same verdict P3-3):
- Removed caption_margin_right (og) and caption_side_padding (square) from
Layout::defaults(). The Imagick renderer never reads them: og text is
left-anchored from logo_x+logo_w+caption_gap; square text is center-anchored
at floor(width/2). Right-edge geometry is enforced by caption_chars_per_line.
Decision: remove (not consume) — no renderer geometry to wire them to.
3. Amortized pv/role (P3 carried, phase-1 thread seq 49 + seq 50):
- Post_Assembler::amortize_research_costs() SELECT now includes prompt_version
and agent_role; INSERT carries them forward so amortized llm_research rows are
no longer stamped with NULL/empty audit fields.
4. fetch_page() error body (P3 carried, phase-1 thread seq 50):
- Runware_Catalog_Fetcher::fetch_page() non-200 exceptions now include up to
200 chars of the response body for log-based diagnosis.
5. cto-review.yml isinstance guard: ALREADY FIXED at HEAD (line 454 uses
c.get("severity", "UNKNOWN")). Noted in CHANGELOG; no code change.
Agent-Session: engineer-prab-maint-20260612