Replaces the per-repo staging/smoke/production jobs with one call to
peptiderepo/peptide-e2e/.github/workflows/deploy-app.yml (target_path=wp-content/themes/peptide-starter).
Validated end-to-end on the calculator pilot.
Agent-Session: cto rollout-reusable-deploy
listPullRequestsAssociatedWithCommit is eventually-consistent after a squash
merge; the single immediate call intermittently flagged legit merges as
'direct push to main'. Now polls up to 5x/10s before opening an issue.
Agent-Session: cto audit-race-fix
- Remove double horizontal padding from .hero-verdict-explainer section
(ps-container inside already provides 24px padding on each side)
- Switch base grid to single column; add 520px breakpoint for 2-col
(below 520px, columns are too narrow for 'Investigational' pill)
- Add min-width: 0 to grid items to prevent implicit size blowout
- Add max-width: 100% to .pr-verdict inside items as overflow guard
- Sync style.css with production state (server had drifted from v2.1.8 HEAD)
Fixes: right-column cards misaligned/clipped on narrow mobile viewports
hero-featured-verdicts, hero-verdict-card, and hero-verdict-explainer
classes were used in front-page.php but had no CSS rules, causing the
Featured Verdicts section to render with bare browser defaults.
- Add grid layout for verdict cards (1-col mobile, 3-col >=900px)
- Add card styling: border, padding, radius, shadow, hover lift
- Tint left border per verdict state via CSS :has()
- Add verdict explainer grid (2-col mobile, 3-col 640px, 5-col 900px)
- Add signal rows, summary, link, and footer button styling
The standalone SSH 'Verify deploy destination' step was causing consistent
connection timeouts (exit 255, ~2min hang) on production deploys. Root cause:
Hostinger rate-limits concurrent SSH connections from different GitHub Actions
runner IPs — the staging job exhausts a connection window and the production
runner (on a different IP) gets timed out by the server.
Fix:
- Remove the standalone SSH verify step that was always the first to time out
- Add ConnectTimeout=30 BatchMode=yes to ALL ssh/rsync commands so failures
surface in 30s instead of the default 120s TCP timeout
- The plugin inventory pre/post check still guards against wrong-path deploys
(the actual safety guarantee we care about from the 2026-04-23 incident)
- rsync itself will fail safely if the target path doesn't exist
v2.1.7 deploy had a truncated functions.php due to bash-mount write lag — missing
require_once for inc/verdict-meta.php and inc/verdict-helpers.php, which caused
a Fatal error on front-page.php:24 (undefined function peptide_starter_get_verdict_taxonomy).
Also adds the Beehiiv attribution enqueue (intended for v2.1.7 but lost in the
truncation). Site was down for ~30 min; production restored via direct SSH upload
before this commit.
- Restore: require_once inc/verdict-meta.php
- Restore: require_once inc/verdict-helpers.php
- Add: peptide_starter_enqueue_beehiiv_attribution() + wp_enqueue_scripts hook
Smoke failures (e.g. Playwright infra issues) should not block reporting
a successful deploy as failed. Root cause of smoke failures fixed in
peptide-e2e@da79ee2 (explicit checkout in workflow_call context).
- Add page-our-methodology.php — two-column ToC template for /our-methodology/
Mirrors page-how-we-review.php; CSS classes use page-our-methodology prefix
#last-verified anchor is deep-link target for Phase 2 verdict-card lines
- Footer section 5: add Our Methodology link between How We Review + Editorial Standards
- Bump version to 2.1.6
Issue 1: badge→title gap tightened from 16px to 8px.
Verdict badge is a label for the peptide name; card's uniform gap: --spacing-md
made them look like separate paragraphs. Fix: margin-top offset on __title.
Issue 2: inter-card gap increased from --spacing-xl (32px) to --spacing-2xl (48px).
Cards were visually merging into a single block. Card-to-card gap must clearly
exceed within-card gaps to maintain the three-card hierarchy.
No functional or template changes — CSS-only.
- Add 'coming_soon' key to module card definitions
- Protocol Builder, Tracker, Subject Log: coming_soon = true
- Calculator: fully active (shortcode_exists passes); no badge, no --inactive
- New .ps-module-card__badge: absolute top-right pill, --gray-200/--gray-700,
Inter 600 10px; layers on top of --inactive dim treatment
- position: relative added to .ps-module-card to anchor the badge
CMO-approved in thread: 2026-04-site-wide-brand-adoption seq 10
page-calculator.php and module-cards.php were both checking for
'peptide_tools_calculator' which the plugin never registered.
The calc plugin (prc) registers 'prc_calculator' — template fell
through to the 'currently being set up' fallback on every request.
The 'Verify deploy destination' step defined DEST on the runner then used
${DEST} inside an SSH command. The remote shell has no DEST variable, so
${DEST} expanded to empty → 'test -f /style.css' → always fails.
Fix: inline the full theme path using ${{ secrets.SSH_USERNAME }} which
the GitHub Actions runner expands to a literal string before the script
is sent to SSH. Remote shell receives a plain path with no variables.
continue-on-error is not supported on reusable workflow (uses:) job calls —
the workflow was failing at setup with no jobs spawned.
Fix: remove smoke from deploy-production needs. Smoke tests still run in
parallel (for visibility) but production no longer waits on them. Re-add
smoke to needs once peptide-e2e suite is stable and exercising staging.
The smoke job calls peptiderepo/peptide-e2e which expects an e2e/ directory
that doesn't exist in this repo. Until that repo and its Playwright tests are
properly wired, a smoke failure must not block production deploy.
continue-on-error: true means tests still run (visible in Actions) but don't
gate the deploy. Remove this flag once the e2e suite reliably exercises the
staging environment.
'test ${PIPESTATUS[0]} -eq 0' sends a literal backslash to bash, which
escapes the dollar sign and prevents variable expansion — test receives the
string '${PIPESTATUS[0]}' instead of an integer, causing exit code 2.
Fix: remove the backslash so bash expands PIPESTATUS correctly.
Four more 'single' keys had incorrect tab counts (same over-indentation
pattern as line 37 fixed in prior commit):
- Line 52 (verdict_text registration): 6 tabs → 3
- Line 66 (signal_row text, inside for loop): 8 tabs → 4
- Line 80 (signal_row glyph, inside for loop): 8 tabs → 4
- Line 97 (has_partner_link): 6 tabs → 3
For-loop body lines 173–175: were at 3 tabs (same level as the 'for'
statement); PHPCS requires body to be indented one level deeper → 4 tabs.
All pre-existing violations in verdict-meta.php are now cleared.
front-page.php:
- Replace 3 decorative multi-line HTML comment blocks (tab+space mixed
indentation) with single-line <!-- SECTION --> comments; eliminates 16
'Tabs must be used' PHPCS errors at lines 37-41, 93-97, 127-132
inc/verdict-meta.php:
- Line 37: correct over-indented 'single' key (6 tabs → 3 tabs to match
array alignment of sibling keys)
- Line 171: split '<?php for (...)' onto two lines so opening PHP tag is
on a line by itself (WordPress PHPCS requirement)
Both are pre-existing violations now exposed because CI runs PHPCS on all
PHP files (not just changed ones). No functional change.
The verdict card was showing 'Updated [WP post creation date]' which doesn't
reflect the editorial last-reviewed date. Showing a wrong date is worse than
showing none. Timestamp removed; will re-add with last_reviewed_date post meta
in v1.1 when the review-cadence tracking system is ready to populate it.
P1.1: verdict_text meta field + card.php wiring
- Register verdict_text (textarea, show_in_rest) on peptide CPT
- card.php reads verdict_text meta; falls back to placeholder if empty
- Hardcoded generic placeholder no longer the default for published posts
- All 3 monographs populated with CMO-authored verdict text
P1.2: per-row glyph meta fields
- Register signal_row_1/2/3_glyph (enum: ✓|!|?|⊘|⚠, show_in_rest)
- card.php reads per-row glyph from meta instead of hardcoding by position
- Missing glyph renders nothing (not a wrong glyph)
- Semaglutide: ✓✓! | BPC-157: ✓!? | Melanotan-II: !!⚠
P1.3: conditional inline disclosure
- Register has_partner_link (boolean, default false, show_in_rest)
- single-peptide.php only renders inline disclosure when has_partner_link=true
- All 3 loaded monographs set to has_partner_link=false
- Footer disclosure unaffected (always renders)
N.1: dark mode toggle hidden
- header.php: toggle button hidden (display:none + aria-hidden)
- Dark-mode verdict colors not validated for v1; re-enable in v1.1
Meta box updated with textarea, glyph dropdowns, and partner-link checkbox.
The engineer registered verdict meta and the meta box against 'pr_peptide'
which does not exist. PR Core registers the CPT as 'peptide'. Result: the
verdict meta box was invisible in wp-admin and meta was not exposed in REST.
All functional register_post_meta and add_meta_box calls now target 'peptide'.
No data migration needed — post meta is keyed by meta_key, not CPT.
- Verdict card component was built in alpha.1 but never called from the
template; no verdict state was rendering on any pr_peptide page.
Now called immediately after the page header for posts with verdict_state.
- Affiliate disclosure (inline) was built in alpha.1 but never called.
Now rendered after .peptide-content-box (below the_content / partner links)
per the editorial disclosure spec: disclosure must follow the partner link.
- Suppress page-header <h1> when verdict_state is set; the verdict card
already renders an <h1>, avoiding duplicate heading semantics / SEO issue.
Remove all WC asset dequeue logic, cart icon conditional, and WC-specific tests from the theme. Eliminates the class of fatal errors seen in the 2026-04-23 incident where is_woocommerce() was called after WC deactivation.
Version: 1.6.x → 1.7.0
Reviewed-by: peptiderepo (CTO)
QA: qa-reviews/peptide-starter-theme/2026-04-23-d239bd1e.md
Two safety nets to prevent rsync --delete wiping the wrong directory:
1. Pre-deploy: verify destination/style.css exists (proves it's a theme dir)
2. Post-deploy: compare active plugin count before and after — fail if any dropped
Addresses root cause of 2026-04-23 theme deploy incident.
Call to undefined function is_woocommerce() in perf-asset-policy.php:69
caused a 500 on all page loads. WooCommerce is not active on this site.
Added function_exists() guard so the WC asset dequeue block is skipped
when WooCommerce is not installed.
When a PR modifies the admin settings surface, file/class structure, or data flow, the QA reviewer now flags the PR as a MAJOR concern unless the PR description references an accompanying update to the CTO app-map at `Peptide Repo CTO/app-maps/<repo-slug>.md`.
The CTO workspace is a separate repo, so CI cannot verify the doc update mechanically — the reviewer inspects the PR description for an explicit mention.
Why: the CTO-level app-maps are the single-pane-of-glass reference that lets the CTO answer questions like 'which settings does this plugin expose?' without grepping the repo each time. Without a merge-gate prompt, these maps drift out of sync with the code.
Co-authored-by: peptiderepo <peptiderepo@users.noreply.github.com>
The theme was rendering featured images at WordPress 'medium' size
(300×300 square crop) instead of the full 1200×632 original. Changed
the_post_thumbnail() from 'medium' to 'full' and added responsive CSS
that scales images to 100% content width with centered alignment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The peptide-starter-theme v1.5.2 release added
peptide_starter_is_cloudflare_peer() — a CF-peer IP validator that
correctly rejects direct-to-origin requests as non-Cloudflare traffic
with HTTP 403. The deploy workflow's post-deploy health check makes
exactly such a request from a GHA runner IP, so it now reliably
receives 403 even on successful deploys.
Two deploys today (peptide-starter-theme v1.5.2, prautoblogger Commit 1a)
both succeeded but reported workflow failure due to this. The actual
deploys (rsync + cache purge) ran clean; site verified HTTP 200 from
real traffic both times.
Fix: accept either 200 (normal healthy response) or 403 (validator
actively rejecting non-CF origin — itself a positive liveness signal)
in the health check. Reject only on 5xx, 4xx-other, or connection
failure.
Reverting this fix is correct only if we either (a) bypass the
validator for our own health-check user-agent, or (b) route the
health check through Cloudflare. Both are larger changes for a
later release.
Agent-Session: cowork-deploy-healthcheck-fix-20260415
Co-authored-by: peptiderepo <peptiderepo@users.noreply.github.com>
Neurometric markets a task-specialized PR-Summarizer SLM (Qwen3-4B +
specialist system prompt) on a free tier. Adding it as a 4th voice in
the existing A/B reviewer panel to see whether a specialized small
model catches things the 3 general-purpose voices miss.
The SLM does not honor OpenAI tool-calling, so it cannot return our
structured submit_review schema. Wired as a "prose voice":
- MODELS tuple gains a 6th provider_type field
("openrouter_tools" | "neurometric_prose")
- call_model() dispatches; new call_neurometric_prose() path hits
api.neurometric.ai/v1 without tools, embeds raw markdown output,
and infers verdict from keyword heuristic
- Render branch in PR comment marks the verdict as heuristic and
notes tokens/cost are not tracked (free tier)
- Never the primary voice; heading still driven by Haiku
Also hardens the shared render path against models that omit the
optional 'summary' field (rev.get('summary') fallback).
Requires new repo secret NEUROMETRIC_API_KEY (already set on all four
peptiderepo repos). Voice self-skips with inline error if missing.
Agent-Session: cowork-neurometric-qa-voice-20260415
Co-authored-by: peptiderepo <peptiderepo@users.noreply.github.com>
Adds the org-wide agent process doc (QA gate, peptiderepo git identity,
300-line cap, doc-in-same-commit, branch naming, commit trailer, PR-only
to main) and rewrites CLAUDE.md as a thin bootstrap pointer to it.
No runtime impact. No code change. Pure process/docs ratification.
Per CTO handoff in convo/prtheme/threads/2026-04-v1.5.2-release-cleanup/
03-cto-reply.md, this is the calibration run for the rollout pattern
across the four peptiderepo repos.
Agent-Session: prtheme/v1.5.2-release-cleanup/claude-opus-4-6
Adds a pointer to the cross-app engineering docs in the CTO workspace so engineers scoped to this repo can find shared reference material (Cloudflare AI Gateway routing, OpenRouter key rotation, interface pattern, image-generation stack, social distributor choice) and the incident runbook.
No code changes. Pure docs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>