feat: PRAB article JSON-LD emitter + meta reader (v0.8.0)

- PR_Core_Jsonld_Article: meta-triggered emitter for PRAutoBlogger posts
  (trigger: _prab_schema_version=1 on post type). Yoast path retypes page
  node to MedicalWebPage (wpseo_schema_webpage_type priority 10) and enriches
  Article piece with citation[], about[]→Drug @id, lastReviewed, honest
  reviewedBy (wpseo_schema_graph priority 13). No-Yoast fallback emits
  standalone @graph. Posts without trigger meta are byte-unchanged.

- PR_Core_Prab_Meta_Reader: sanitises all _prab_* contract-v1 meta at read
  time. URLs validated (http/https), DOIs normalised to https://doi.org/ URI,
  JSON arrays per-element validated, WP user ID resolved. Malformed values
  degrade gracefully. Honest reviewedBy: Person ONLY when mode=human + valid
  user ID; else Organization. Never a fabricated person.

- Unit tests: JsonldArticleTest.php — 22 assertions covering is_triggered,
  review_mode, reviewed_by Person/Org decision tree, citation sanitization,
  DOI normalisation, about linkage, retype passthrough, enrich, no-new-nodes,
  editorial-system-never-person.

- bootstrap.php: WP_User stub + get_userdata reads pr_test_userdata global.
- ARCHITECTURE.md: updated JSON-LD class tree + PRAB emission section.
- CONVENTIONS.md: PRAB contract v2 extension guide added.
- CHANGELOG.md + version bump to v0.8.0.

Ratified contract: convo/prcore/decisions/2026-06-11-jsonld-contract-v1.md
File sizes: article.php=235L, meta-reader.php=265L (both < 300-line gate).
No duplicate Article/WebPage nodes. uninstall.php unaffected (_prab_* unowned).

Agent-Session: prcore-jsonld-article-20260622
This commit is contained in:
peptiderepo
2026-06-23 04:23:21 +00:00
parent a7a2bb2f6d
commit 1ce471981b
9 changed files with 950 additions and 4 deletions

View File

@@ -4,6 +4,52 @@ All notable changes to Peptide Repo Core are documented here.
Format: [Semantic Versioning](https://semver.org/).
## [0.8.0] — 2026-06-23
### Added
- **PRAutoBlogger article JSON-LD emitter** (ratified contract v1 — `convo/prcore/decisions/2026-06-11-jsonld-contract-v1.md`):
- `PR_Core_Jsonld_Article` (`frontend/class-pr-core-jsonld-article.php`, ~235 lines) — meta-triggered
emitter for `post` posts carrying `_prab_schema_version=1`. Hooks into Yoast's graph via
`wpseo_schema_webpage_type` (priority 10) and `wpseo_schema_graph` (priority 13). Retypes the
page node to `MedicalWebPage`; enriches the Yoast `Article` piece with `citation[]`,
`about[]` (Drug `@id` stubs), `lastReviewed`, and `reviewedBy`. Standalone `@graph` fallback
(Article + MedicalWebPage) when Yoast is absent. Posts without `_prab_schema_version` meta
are byte-unchanged.
- `PR_Core_Prab_Meta_Reader` (`frontend/class-pr-core-prab-meta-reader.php`, ~268 lines) — reads
and sanitises all contract-v1 `_prab_*` meta at read time (not trusting PRAB's write-time
sanitization). URLs validated (http/https only), DOIs matched against canonical pattern, JSON
arrays validated per-element, WP user ID resolved via `get_userdata()`. Malformed values
degrade gracefully (field skipped) — no page-render fatals.
- **Honest `reviewedBy`:** Person node emitted ONLY when `_prab_review_mode=human` AND
`_prab_reviewed_by` resolves to an existing WP user. All other cases (editorial-system mode,
missing/zero/nonexistent user ID) emit the Organization node ("Peptide Repo"). Never emits a
fabricated person — the core contract guarantee.
- **`about` Drug linkage:** `_prab_about_peptides` (JSON array of peptide post IDs) is resolved
to Drug stub arrays using the stable `{permalink}#drug` @id established in v0.6.0. Each ID
must resolve to a published `peptide` post; unresolvable IDs are skipped.
- **Citation nodes:** `ScholarlyArticle` when DOI present (DOI normalised to https://doi.org/
URI as `sameAs`), else `CreativeWork`. `quality_score` never emitted (no schema.org mapping
per contract v1).
- **No duplicate nodes:** integrates via Yoast mutation (priority 13, after PR_Core_Jsonld
priority-12 Drug/FAQ injection). Never adds new WebPage or Article pieces.
- Unit tests: `tests/unit/JsonldArticleTest.php` — 22 assertions covering is_triggered,
review_mode, reviewed_by (Person/Org decision tree), citation sanitization, about linkage,
retype, enrich, no-new-nodes, untriggered passthrough, editorial-system-never-person.
### Changed
- `class-pr-core.php`: boots `PR_Core_Jsonld_Article` alongside `PR_Core_Jsonld` in `init()`.
- `tests/bootstrap.php`: enhanced `get_userdata()` stub to read from `$GLOBALS['pr_test_userdata']`;
added `WP_User` class stub; initialised `$GLOBALS['pr_test_userdata']` global.
- `ARCHITECTURE.md`: JSON-LD class table updated with new classes; §2.7 PRAB article emission added.
- `CONVENTIONS.md`: JSON-LD extension guide updated with PRAB-article hook pattern.
### Technical
- Meta keys `_prab_*` are owned by PRAutoBlogger namespace (PRAB registers/writes; prcore reads
only). `uninstall.php` unaffected — prcore never writes `_prab_*` meta, so no teardown needed.
- Yoast hook order: `wpseo_schema_graph` priority 11 (peptide MedicalWebPage enrich) → priority 12
(Drug/FAQ inject) → priority 13 (PRAB Article enrich + page retype). Three priorities prevent
race conditions between the peptide and article enrichment paths.
## [0.7.1] - 2026-06-17
### Fixed