Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/ci/asset-audit.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@
$name = 'screenshot-' . $n . '.png';
if ( $name !== ( $shot['filename'] ?? '' ) || (string) $n !== $captions[$i][1] || $shot['caption'] !== $captions[$i][2] ) { $fail( 'screenshot numbering/caption mismatch' ); }
if ( ! is_int( $shot['width'] ?? null ) || ! is_int( $shot['height'] ?? null ) || $shot['width'] < 772 || $shot['width'] > 1280 || $shot['height'] < 200 || $shot['height'] > 1600 ) { $fail( 'unexpected screenshot canvas' ); }
if ( 5 === $n ) {
if ( 4 === $n ) {
$visible = $shot['visible_ui_text'] ?? '';
if ( ! is_string( $visible ) || ! str_contains( $visible, 'left the newer value unchanged' ) ) {
$fail( 'screenshot-5 missing conflict explanation proof' );
$fail( 'screenshot-4 missing conflict explanation proof' );
}
}
$canonical[$name] = array( $shot['width'], $shot['height'] );
Expand Down
31 changes: 31 additions & 0 deletions docs/review/279/CAPTIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# #279 screenshot captions (paste block)

Do not paste this into `wordpress/writeleash/readme.txt` until `wordpress/assets/screenshot-1.png` through `screenshot-6.png` are real captures from the commit that ships them. The PNGs in the tree today are v0.1 images. Applying these captions while those files remain would make the listing lie.

Update `readme.txt` in the same commit as the new PNGs. Delete every `Earlier …` line in `== Screenshots ==`, including `Earlier authentic captures; current labels and controls may differ.` Do not keep `Not all features are pictured.` The replacement section is the block below, verbatim.

Issue #281 will change Results/History outcome copy after this prep. Shots 4 and 5 are not captured in this pass.

## Paste into `== Screenshots ==`

```
== Screenshots ==

1. Select products by name, SKU, category or ID – with nested subcategory option.
2. Exact before-and-after Preview of Regular & Sale prices (including variations).
3. Live background job progress with Resume.
4. Conflict protection: newer price is kept instead of overwritten.
5. History + eligible Undo within 30 days.
6. Safety limits: max products, max % increase/decrease, block zero prices.
```

## Shot map (not for readme.txt)

| File | Caption | This pass |
| --- | --- | --- |
| screenshot-1.png | Select products by name, SKU, category or ID – with nested subcategory option. | Not captured. v0.1 file must not be reused. |
| screenshot-2.png | Exact before-and-after Preview of Regular & Sale prices (including variations). | Not captured. v0.1 file must not be reused. |
| screenshot-3.png | Live background job progress with Resume. | Not captured. v0.1 file must not be reused. |
| screenshot-4.png | Conflict protection: newer price is kept instead of overwritten. | BLOCKED until #281 is on the branch. Do not ship a Results frame under this name. |
| screenshot-5.png | History + eligible Undo within 30 days. | BLOCKED until #281 is on the branch. Do not ship a History frame in this pass. |
| screenshot-6.png | Safety limits: max products, max % increase/decrease, block zero prices. | Not captured. v0.1 file is History, not this screen, and must not be reused. |
21 changes: 21 additions & 0 deletions docs/review/279/CAPTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# #279 how a real capture is produced

This prep did not capture anything. `docker info` fails in this environment (exit 1). Do not invent a site URL, a container, or a WooCommerce admin.

## Existing harness (not sufficient, and not run here)

`wordpress/tests/admin/selection-browser-run.sh` is the only in-repo listing capture path. It needs Docker Compose (`wordpress/tests/admin/docker-compose.yml`, project `writeleash_woo111`), a disposable WordPress + WooCommerce 11.1.2 site, and Playwright Chromium. On MySQL/default cache it seeds `wordpress/tests/admin/listing-browser-fixture.php` with `WL167_LISTING_MODE=seed` and runs `wordpress/tests/admin/listing-capture.cjs`.

That script requires `WL167_BASE_URL` and `WL167_LISTING_FIXTURE`. It logs into the disposable admin, sets a 1280×900 viewport, and writes `listing-1-select.png` … `listing-6-history.png` under `WL167_EVIDENCE` only. It does not commit PNGs. It does not know the #279 caption order, nested-subcategory frame, safety-limits frame, or the `$100 / $120 / $80` conflict. Its conflict seed writes `$75.00`. Its progress assertion is the older "Progress and results" / "remaining" copy, not proof of the live progress bar.

Do not point that script at `wordpress/assets/` and do not rename its evidence onto `screenshot-*.png`.

## Later capture (when a live disposable site exists)

1. Confirm `docker info` works. Build the disposable site from the commit that will ship, English admin, USD, two decimals, debug display off.
2. Seed the catalog in `FIXTURE.md`. Do not load customer data.
3. Set `WL279_BASE_URL` to that site. `docs/review/279/capture-refuse.cjs` exits before any image write if the variable is missing, not http(s), or not responding. It also exits if asked to copy `wordpress/assets/screenshot-*.png`. It never writes a PNG.
4. Capture only from the live admin, full pixels from the browser, PNG, ≥1200×900, <1MB. Files stay `screenshot-1.png` … `screenshot-6.png`.
5. Do not capture shots 4 or 5, or any Results/History frame, until #281 is on that same branch. Outcome copy must be the copy that ships.
6. In one commit: replace the six PNGs, paste `CAPTIONS.md` into `readme.txt`, delete every `Earlier …` line, and fill `PROVENANCE.md` (capture date, source commit, dimensions, SHA-256, viewport, browser). Reject any file whose SHA-256 matches the must-not-reuse table.
7. Do not scale, crop, or composite the v0.1 PNGs. Do not add banners, icons, or an accessibility-certified claim.
34 changes: 34 additions & 0 deletions docs/review/279/FIXTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# #279 Mixed catalog fixture notes

No catalog was seeded in this prep. `docker info` fails here, so there is no disposable site. These notes describe the synthetic catalog a later capture must use. They are not evidence that the catalog exists.

No customer data. No real orders, emails, names, or payment details. No `WP_DEBUG` notices, Query Monitor, or admin debug bars in the viewport. English admin (`en_US`). Store currency USD, two decimal places, amounts rendered as `$… USD`. Disposable local admin only.

The in-repo seed `wordpress/tests/admin/listing-browser-fixture.php` is the #182 listing fixture (`WL Listing` products). It is not this catalog: it does not open nested subcategories, it moves the conflict row from `$100.00` to `$75.00` rather than `$120.00`, and it has no safety-limits viewport. `wordpress/tests/acceptance/dirty-catalog.php` is a corruption-tolerance leg, not a screenshot catalog. The historical "Mixed catalog" named in `docs/visual-assets-v0.1.md` and `wordpress/release/assets-122/proof.json` was a retained local #188 fixture; its seed is not in this tree. Do not recaption those v0.1 PNGs as this fixture.

## Catalog

Parent category `Apparel`, child `Tees` (one nested subcategory). Variable parent in `Tees` expands to variations. Simple products may sit in `Apparel` only.

| Product | Where | Prices (USD) | Role |
| --- | --- | --- | --- |
| Canvas tote | Apparel (direct) | Regular `$36.00` | Name/category selection |
| Cotton tee — Small, SKU `TEE-SMALL` | Tees variation | Regular `$24.00`, sale `$20.00` | Variation identity in Preview |
| Cotton tee — Large, SKU `TEE-LARGE` | Tees variation | Regular `$28.00`, sale `$22.00` | Variation identity in Preview |
| Clean ceramic mug | Apparel | Regular `$18.00` | Simple row; not a damaged-price skip story |
| Notebook, known product ID | none required | Regular `$12.00` | Manual ID selection |
| Price guard sample | Apparel | Regular `$100.00` at review | Conflict row |

Selection shot: English Products → Bulk Prices. Show name/SKU search, Product category, Advanced manual product IDs, and the **Include subcategories** checkbox enabled, with the sentence that nested subcategories are included once and variable parents expand to variations. Do not show the old "subcategories are not included" state as the pictured option.

Preview shot: one saved Preview that shows exact before-to-after for both price fields across the set, including the two Cotton tee variations. Current Preview column is `{Regular price\|Sale price} before to after`, plus Delta. Planned stored prices are not shopper prices. Do not approve in this frame.

Progress shot: a small in-progress job (the #182 sample is 24 products, 8 stepped, 16 remaining — do not describe any frame as a pictured 1,000-product run). Viewport must show the current live Apply progress bar and **Resume remaining products**. Not the pre-live-progress v0.1 page.

Conflict shot (do not capture until #281 is on the branch): review Regular `$100.00`, plan Set `$80.00`, then a separate Woo edit sets Regular to `$120.00` before Apply. Result row must show expected `$100.00 USD`, now `$120.00 USD`, planned `$80.00 USD`, newer value kept. Current headers are `Regular price expected`, `Regular price now`, `Regular price planned`. #281 may change outcome copy; capture only after that copy is what will ship. Do not use the #182 `$75.00` mutation.

History shot (do not capture until #281 is on the branch): History table with an eligible Undo row, `Undo available for prices changed by this job.` and `Until {site time}` inside the default 30-day window (`Undo_Repository::retention_days()` default 30). Availability is not guaranteed restoration. No completed-Undo claim. No Results/History frame in this prep.

Safety-limits shot: open `Safety limits (optional)` (`#writeleash-free-safety-limits`). Custom values keep the details open. Show maximum changing products (0–1000; picture a tightened value such as 50, not a 1,000-product run), maximum increase percent, maximum decrease percent, and **Block a preview that sets any changing price to zero** checked. Visible copy includes `A change beyond these limits blocks the whole preview.` Defaults in code are max products 1000, increase 50, decrease 50, warning threshold 20, block-zero off — a shipping frame should show the tightened custom limits, not a collapsed summary.

Shipping files, when eventually captured: `screenshot-1.png` … `screenshot-6.png` only. PNG, at least 1200×900, under 1MB, English, USD. No banners, icons, or extra names.
35 changes: 35 additions & 0 deletions docs/review/279/PROVENANCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# #279 screenshot provenance

Captured 2026-10-14 from the disposable acceptance lab, not from reused v0.1 files.

| Field | Value |
| --- | --- |
| Capture date (UTC) | 2026-10-14T15:58:00Z through 2026-10-14T16:00:00Z |
| Source build | `df8d804842425bdcf92c4b8eb5df8004314420c6` (origin/main after #285) |
| Lab | `http://127.0.0.1:18092` — Docker project `writeleash_woo112`, Server 29.5.2 |
| Images | `wordpress:7.1.2-php8.2-apache@sha256:da4c3e7b0051b70835b0a188ecdd5bce5ebf6f83d1f3df41553f1a97d237fd19`, `wordpress:cli-php8.2@sha256:aaa79b1239f24fccbb1634ec0a25c3e4fac6271bc9bf2334c40c3c8ef77bce89` |
| WooCommerce | 11.1.2, ZIP SHA-256 `9de9350a1cf5671b9960afb3151f40f7980e223217a441bf2ea5921b5fce8e9e` |
| Admin | English, USD, published simple products and variations created with WooCommerce CRUD |
| Browser | Google Chrome 148.0.7778.178 via Playwright viewport screenshots (no browser chrome) |

Shot 1 is 1280×1600 so name, SKU, category, product ID, and the nested subcategory control fit in one frame. The listing audit rejects width above 1280. Shots 2–6 are 1280×960. None match the v0.1 hashes below.

| File | Dimensions | SHA-256 | Viewport | Visible claim |
| --- | --- | --- | --- | --- |
| screenshot-1.png | 1280×1600 | `efeffac78ebd9d0968708ac92b9e754b415192333b690f2a124f9350ec21927d` | 1280×1600 | Product name or partial SKU, One exact SKU, Product category, product IDs, Include subcategories, Apparel › Shirts |
| screenshot-2.png | 1280×960 | `f0d498e843f3378ca57c491ef2963b28fa3f384141f62e11be9c46146bacc417` | 1280×960 | Sale price before to after, Harbor Tee variations, regular price preserved |
| screenshot-3.png | 1280×960 | `93dad52dc9a9ae8ddb4663bb341deca54a149cf0a037a1d1d86a32870da014eb` | 1280×960 | Progress and results, Resume remaining products |
| screenshot-4.png | 1280×960 | `0947f52432cc673cc103cc69d54af84aeba42f82cf9c292debdc142d0efa59d2` | 1280×960 | Newer price kept; $100.00 expected, $120.00 now, $80.00 planned; left the newer value unchanged |
| screenshot-5.png | 1280×960 | `082e583bb7c1af6605f45af5e00deda7c040b175225bab56dde1ad7910426a33` | 1280×960 | History; Undo available until November 13, 2026 (30 days after October 14, 2026) |
| screenshot-6.png | 1280×960 | `24e8cf161074df8e0a2cabf90c5c57af9d83f4c698e29e3dac9bae41dca48a71` | 1280×960 | Maximum changing products, maximum increase percent, maximum decrease percent, block zero prices |

## v0.1 files — must not reuse

| File | SHA-256 (must not reuse) |
| --- | --- |
| screenshot-1.png | `78adbbc08784c716f0c6de62ea7fba2da83bfea40e986bddd70112a391a7819a` |
| screenshot-2.png | `543326ae8ff365407d6cd0d637c28bf55c5ac504d80fdcf6f641e50076833d03` |
| screenshot-3.png | `a12d8a9a0e2413d3c54c75f66194fc6eef68e44e91d2e6e1152d39b343a8227b` |
| screenshot-4.png | `a5ebbd44629931c4788ee4624a0b96dfb233b54b9c6bff448655a1cfe1175e37` |
| screenshot-5.png | `5181b4fba8643483cc0b57c2ebeffe4eba61c69ed278b6efd91d2b6d8dd9f956` |
| screenshot-6.png | `df7c40f4552bd8f9511e5c9320756fa5efba30cc834a0665bba78c476428d767` |
67 changes: 67 additions & 0 deletions docs/review/279/capture-refuse.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// #279 prep skeleton. Refuses unless a live disposable site URL is set.
// Never copies wordpress/assets/screenshot-*.png. Never writes a PNG.
const http = require('node:http');
const https = require('node:https');
const path = require('node:path');

const OLD = [
'wordpress/assets/screenshot-1.png',
'wordpress/assets/screenshot-2.png',
'wordpress/assets/screenshot-3.png',
'wordpress/assets/screenshot-4.png',
'wordpress/assets/screenshot-5.png',
'wordpress/assets/screenshot-6.png',
];

function die(message) {
console.error('listing-capture-279: ' + message);
process.exitCode = 1;
}

function looksLikeCopy(value) {
const text = String(value);
return OLD.some((asset) => text.includes(asset) || text.includes(path.basename(asset)))
|| /copy|screenshot-\d\.png/i.test(text);
}

const args = process.argv.slice(2);
if (process.env.WL279_COPY_OLD_ASSETS || args.some((arg) => looksLikeCopy(arg))) {
die('refusing to copy old listing assets');
return;
}

const base = process.env.WL279_BASE_URL;
if (!base) {
die('refusing: WL279_BASE_URL (live disposable site) is required');
return;
}

let url;
try {
url = new URL(base);
} catch (error) {
die('refusing: WL279_BASE_URL is not a URL');
return;
}
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
die('refusing: WL279_BASE_URL must be http or https');
return;
}

const client = url.protocol === 'https:' ? https : http;
const request = client.request(url, { method: 'GET', timeout: 5000 }, (response) => {
response.resume();
if (response.statusCode < 200 || response.statusCode >= 400) {
die('refusing: WL279_BASE_URL is not a live site (HTTP ' + response.statusCode + ')');
return;
}
die('refusing to write PNGs. Shots 4 and 5 are BLOCKED until #281 is on the branch. Do not copy wordpress/assets/screenshot-*.png.');
});
request.on('timeout', () => {
request.destroy();
die('refusing: WL279_BASE_URL did not respond');
});
request.on('error', () => {
die('refusing: WL279_BASE_URL is not a live site');
});
request.end();
Binary file modified wordpress/assets/screenshot-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wordpress/assets/screenshot-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wordpress/assets/screenshot-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wordpress/assets/screenshot-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wordpress/assets/screenshot-5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wordpress/assets/screenshot-6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading