# Site Content catalog

Audience: AI coding agents first.

**Outcome:** deliver the dormant `SiteContentCatalog` primitive that deterministically discovers supported Site Content entities and records exclusions, without activating Site Content in WordPress.

**Status:** DONE — `SC-CATALOG-01` is published at `555047b3558ff526c5df772526a20d47b4224cf9` on `origin/master`. It remains dormant with no runtime deployment. Blocker investigation limit: 25 minutes per blocker.

## Task IDs

- `SC-CATALOG-01` — dormant Site Content catalog primitive and focused contract test.

## Source request

Create the next durable Site Content delivery plan after published request contexts. Use preserved behavior evidence from `.worktrees/ipz-site-content-persistence-v2`, especially `SiteContentCatalog` and its direct dependencies; select the smallest independently releasable dormant catalog slice without copying implementation.

## Acceptance criteria

1. Add one dormant `SiteContentCatalog` primitive and one focused unit test that reconstruct the preserved public contract without copying its implementation.
2. The catalog supports only `wp_template`, `wp_template_part`, `wp_navigation`, and `wp_block`; type ordering, validation, search, pagination, identity resolution, and source revisions are deterministic.
3. It reads block templates only through `get_block_templates()` and persisted entities only through `get_posts()` with the preserved supported statuses and deterministic ID ordering.
4. It excludes invalid identities, empty source, unsupported/no-translatable block documents, and unsynced reusable patterns with stable reason values; classic themes expose no template rows.
5. It consumes the already-published `BlockSegmentCodec` and `SiteEntityIdentity` contracts unchanged. It has no repository, translation adapter, resource handler, request context, hook, route, REST registration, UI, migration, schema, feature flag, bootstrap registration, or active consumer.
6. Focused deterministic tests cover the public catalog contract and run without a remote system. PHP syntax, focused PHPUnit, focused PHPStan, candidate-aware PHPCS, registration/consumer search, whitespace/diff checks, and applicable hooks pass or any pre-existing legacy-tool limitation is recorded without suppression.

## Exact scope

### Allowed paths

- `plugins/international-press-zone/includes/SiteContent/class-sitecontentcatalog.php`
- `plugins/international-press-zone/tests/Unit/SiteContent/SiteContentCatalogTest.php`
- `plugins/international-press-zone/docs/plans/2026-08-14-site-content-catalog.md`
- `plugins/international-press-zone/docs/plans/INDEX.md`

### Excluded paths and work

- Every other product, test, build, fixture, baseline, autoload, bootstrap, admin, REST, CLI, migration, schema, flag, repository, adapter, runtime, and deployment path.
- Changes to `class-blocksegmentcodec.php`, `class-siteentityidentity.php`, or `class-sitecontentrequestcontext.php`.
- Any remote WordPress, browser, or dev1/dev3/devzone-wordpress-snappy contact.
- Copying preserved WIP implementation rather than independently reconstructing its observed contract.

## Activation state

Dormant and unregistered. The class may be autoloadable through existing conventions but must have no instantiated consumer or WordPress-visible effect. No feature flag is needed because this compatible internal primitive is inactive.

## Preserved evidence

- `.worktrees/ipz-site-content-persistence-v2/plugins/international-press-zone/includes/SiteContent/SiteContentCatalog.php` defines the evidence-only catalog contract.
- Its direct dependencies are `BlockSegmentCodec` for supported-block detection and `SiteEntityIdentity` for stable catalog IDs and identity matching. Published equivalents are already present at `includes/SiteContent/class-blocksegmentcodec.php` and `includes/SiteContent/class-siteentityidentity.php`.
- `.worktrees/ipz-site-content-persistence-v2/plugins/international-press-zone/tests/Unit/SiteContent/SiteContentCatalogTest.php` supplies behavior evidence for supported entities, exclusions, resolution, and classic-theme behavior.
- `2026-08-14-site-content-request-contexts.md` records that request contexts are published and remain inactive; this slice must not consume them.

## Execution steps

1. Before implementation, assign a named worker and change this plan to ACTIVE with the worker identity and start receipt.
2. Compare the preserved public behavior with the published codec and identity contracts; define a minimal independent implementation plan before writing code.
3. Implement only the catalog and focused test in the allowed paths.
4. Verify no registration or active consumer was introduced, run bounded local gates, obtain independent review, then deliver through the established controller.
5. Record commit, publication, validation, activation, and rollback evidence. Mark DONE only after publication is verified.

## Blocker limit

A worker may spend at most 25 minutes investigating one blocker. On expiry, stop that lane, record the exact failing command/output and affected path here, preserve WIP, and use the established escalation path. Do not bypass gates or broaden scope.

## Rollback

Before activation, rollback is a clean revert of the delivery commit affecting only `class-sitecontentcatalog.php` and `SiteContentCatalogTest.php`; no data, schema, cache, route, or runtime state exists to migrate or clean up. Verify the reverted tree has no catalog registration or consumer and rerun the applicable local syntax and focused tests.

## Current receipt

2026-08-14: Planning only. Published request contexts are recorded as complete at commit `442c836eed6a594e56adbd1d2a48deafc7db22e1`. The preserved catalog evidence was read with its direct dependencies and focused test. The current worktree already contains published `class-blocksegmentcodec.php`, `class-siteentityidentity.php`, and `class-sitecontentrequestcontext.php`; no `SiteContentCatalog` class is present. No product code, remote system, test execution, or commit was performed.

2026-08-14: Claude Code began `SC-CATALOG-01` in the isolated `ipz-site-content-catalog` worktree. Before implementation it read this plan, the published request-context plan, `BlockSegmentCodec`, `SiteEntityIdentity`, and the preserved catalog source/test evidence. Investigation is limited to 25 minutes per blocker. Scope remains frozen to the four allowed records; no bootstrap is planned unless evidence proves it necessary.

2026-08-14: The dormant catalog primitive and focused contract test are implemented with no bootstrap change. The published `SiteEntityIdentity` contract uses `catalog_id()` and a `v1_` plus 64-hex-character ID; the catalog reconstructs that published contract rather than the obsolete preserved camel-case/base64 evidence. Syntax passed for both added PHP files; focused PHPUnit passed (4 tests, 15 assertions); focused PHPStan passed with `phpstan.neon.dist`; whitespace check passed; and the source search found no registration or runtime consumer. The first validation attempt exposed absent local Composer dependencies; `composer install --no-interaction --prefer-dist` installed the locked development tools without changing tracked dependency records. Exact source PHPCS passed after PHPCBF applied 27 safe formatting fixes and required API documentation. The focused test's direct WordPress PHPCS run remains non-zero only because the prescribed camel-case test filename and the existing Site Content namespaced fixture pattern conflict with legacy filename, single-namespace, and procedural-test rules. No suppression or baseline was added. The slice remains dormant and unregistered.

2026-08-14: The current local commit contains only the catalog primitive, focused test, and plan registry records. The pre-commit gate passed PHPCS and PHPStan for the staged catalog source. Its notices are benign and accounted for: root JavaScript/TypeScript has no root package, the focused test is outside the hook's PHP ruleset/config paths but was run directly above, Trivy is not installed, and no root Composer lock exists. Publication was deliberately not performed in this task; the catalog remains dormant with no registration, route, consumer, migration, flag, or runtime effect.

2026-08-14: The catalog now excludes every duplicate canonical identity with `duplicate_canonical_identity`, so neither colliding source/template row remains listable. Pagination accepts only bounded positive integers; invalid values throw `InvalidArgumentException`, and an extreme page returns an empty page without calculating an overflowing offset. Focused PHPUnit passed (6 tests, 26 assertions), syntax and PHPStan passed, source PHPCS and diff whitespace passed. The catalog remains dormant.

2026-08-14: Persisted entity IDs now require either a positive integer or a canonical decimal string that round-trips unchanged. The catalog rejects castable and lossy values including `31evil`, leading-zero, signed, zero, and fractional forms before identity construction. A canonical string (`32`) remains accepted. Focused PHPUnit passed (7 tests, 28 assertions); syntax, PHPStan, and source PHPCS passed. The duplicate-collision and hostile-pagination protections remain covered and unchanged; no registration or runtime activation was added.

2026-08-14: Delivery controller publication is verified. Commit `555047b3558ff526c5df772526a20d47b4224cf9` (`Add dormant site content catalog`) is an ancestor of the fetched `origin/master`; its delivery-controller receipt is `4454d3965900e8e3fcafc2c6a8566171512c9d12` (`harness: land worktree-ipz-site-content-catalog at 555047b3558ff526c5df772526a20d47b4224cf9`). Independent review is clean. Focused PHPUnit passed (7 tests, 28 assertions); PHPStan, PHPCS, PHP syntax, and applicable hooks are clean. The catalog remains dormant and unregistered, so no runtime deployment applies.

## Next executable action

None. This delivery is complete; retain the dormant state until a separately planned consumer is approved.
