diff --git a/.github/ci/asset-audit.php b/.github/ci/asset-audit.php index 6ca7465c..dae07023 100644 --- a/.github/ci/asset-audit.php +++ b/.github/ci/asset-audit.php @@ -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'] ); diff --git a/docs/review/279/CAPTIONS.md b/docs/review/279/CAPTIONS.md new file mode 100644 index 00000000..f329d4d4 --- /dev/null +++ b/docs/review/279/CAPTIONS.md @@ -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. | diff --git a/docs/review/279/CAPTURE.md b/docs/review/279/CAPTURE.md new file mode 100644 index 00000000..36ab93bb --- /dev/null +++ b/docs/review/279/CAPTURE.md @@ -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. diff --git a/docs/review/279/FIXTURE.md b/docs/review/279/FIXTURE.md new file mode 100644 index 00000000..3a7efc5d --- /dev/null +++ b/docs/review/279/FIXTURE.md @@ -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. diff --git a/docs/review/279/PROVENANCE.md b/docs/review/279/PROVENANCE.md new file mode 100644 index 00000000..bb467f85 --- /dev/null +++ b/docs/review/279/PROVENANCE.md @@ -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` | diff --git a/docs/review/279/capture-refuse.cjs b/docs/review/279/capture-refuse.cjs new file mode 100644 index 00000000..fc566fc3 --- /dev/null +++ b/docs/review/279/capture-refuse.cjs @@ -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(); diff --git a/wordpress/assets/screenshot-1.png b/wordpress/assets/screenshot-1.png index 75056669..f06587db 100644 Binary files a/wordpress/assets/screenshot-1.png and b/wordpress/assets/screenshot-1.png differ diff --git a/wordpress/assets/screenshot-2.png b/wordpress/assets/screenshot-2.png index 934fde3d..4834b675 100644 Binary files a/wordpress/assets/screenshot-2.png and b/wordpress/assets/screenshot-2.png differ diff --git a/wordpress/assets/screenshot-3.png b/wordpress/assets/screenshot-3.png index 6f1c17f2..e4991231 100644 Binary files a/wordpress/assets/screenshot-3.png and b/wordpress/assets/screenshot-3.png differ diff --git a/wordpress/assets/screenshot-4.png b/wordpress/assets/screenshot-4.png index 23085e9b..5cb528ef 100644 Binary files a/wordpress/assets/screenshot-4.png and b/wordpress/assets/screenshot-4.png differ diff --git a/wordpress/assets/screenshot-5.png b/wordpress/assets/screenshot-5.png index e800d800..48a495d2 100644 Binary files a/wordpress/assets/screenshot-5.png and b/wordpress/assets/screenshot-5.png differ diff --git a/wordpress/assets/screenshot-6.png b/wordpress/assets/screenshot-6.png index 4d9c37c9..046ba9bc 100644 Binary files a/wordpress/assets/screenshot-6.png and b/wordpress/assets/screenshot-6.png differ diff --git a/wordpress/release/assets-122/proof.json b/wordpress/release/assets-122/proof.json index d2dbb534..8406214f 100644 --- a/wordpress/release/assets-122/proof.json +++ b/wordpress/release/assets-122/proof.json @@ -1,16 +1,16 @@ { - "product_base": "a5a736b9d77308afd7534f23e7950b064aea767a", - "guidance_review_date": "2026-10-02", + "product_base": "df8d804842425bdcf92c4b8eb5df8004314420c6", + "guidance_review_date": "2026-10-14", "guidance_url": "https://developer.wordpress.org/plugins/wordpress-org/plugin-assets/", "fixture": { "wordpress": "7.1.2", "woocommerce": "11.1.2", "php": "8.2.32", "database": "MySQL 8.0.44", - "browser": "Google Chrome 154.0.8037.57 (Playwright)", + "browser": "Google Chrome 148.0.7778.178 (Playwright)", "currency": "USD", "price_decimals": 2, - "data": "Real WooCommerce 11.1.2 listing fixture: regular/sale/variable products, results, conflicts, progress and history states.", + "data": "Disposable acceptance lab writeleash_woo112 at http://127.0.0.1:18092. English admin, USD, WooCommerce CRUD Mixed catalog. Captured 2026-10-14.", "scheduler_interruption": "DISABLE_WP_CRON=true; Action Scheduler async runner disabled in disposable fixture only" }, "runtime_manifest_sha256": "d30e8952a0364ac4a7e254d0b44a2ea98eea2df9fcc9f5ff6579ab5427cda891", @@ -57,97 +57,81 @@ { "filename": "screenshot-1.png", "width": 1280, - "height": 900, + "height": 1600, "format": "PNG", - "sha256": "78adbbc08784c716f0c6de62ea7fba2da83bfea40e986bddd70112a391a7819a", - "captured_at_utc": "2026-10-05T22:53:47.382416Z", - "real_state": "Select products and choose the price target", - "caption": "Earlier selection-screen example: choose products by name, SKU or category. Current category selection also offers nested subcategories.", - "visible_ui_text": "WriteLeash Bulk Prices\nSelect products and preview every regular-price or sale-price change before it runs.\n1. Select products\n2. Choose the price change\nPrice to change\nRegular price\nSale price\n3. Safety limits\nPreview price changes\nNothing is saved until you approve the preview.", - "captured_product_base": "a5a736b9d77308afd7534f23e7950b064aea767a" + "sha256": "efeffac78ebd9d0968708ac92b9e754b415192333b690f2a124f9350ec21927d", + "captured_at_utc": "2026-10-14T16:00:00Z", + "viewport": "1280x1600", + "browser": "Google Chrome 148.0.7778.178", + "source_commit": "df8d804842425bdcf92c4b8eb5df8004314420c6", + "lab_url": "http://127.0.0.1:18092/wp-admin/admin.php?page=writeleash-bulk-prices", + "caption": "Select products by name, SKU, category or ID – with nested subcategory option.", + "visible_ui_text": "Product name or partial SKU\nHarbor\nProduct category\nApparel › Shirts · Category ID: 17\nInclude subcategories\nnested subcategories\nExplicit product IDs (advanced), e.g. 12,34,56\nOne exact SKU\nWL-JACKET" }, { "filename": "screenshot-2.png", - "width": 1238, - "height": 1442, + "width": 1280, + "height": 960, "format": "PNG", - "sha256": "543326ae8ff365407d6cd0d637c28bf55c5ac504d80fdcf6f641e50076833d03", - "captured_at_utc": "2026-10-07T04:28:55.750290+00:00", - "real_state": "Real prepared local #188 Woo Admin fixture; minimal static capture for #195", - "caption": "Review exact before-and-after Sale Price values, variations, warnings and skips in this earlier Preview example.", - "visible_ui_text": "Review price change\nSet sale prices to $20.00 USD · 5 products (2 variations)\nSale price before\tSale price after\nCotton tee — Small\nSKU: TEE-SMALL · Variation #29\n$24.00 USD\t$20.00 USD\nCotton tee — Large\nSKU: TEE-LARGE · Variation #30\n$28.00 USD\t$20.00 USD\nApprove and apply", - "captured_product_base": "2e059cacf46977cc3ae1eba15eba628ad6e7570e", - "capture_job_id": "5b36537d-13d8-40ca-993f-2f2e428e7918", - "capture_scope": "Existing synthetic Mixed catalog; no fixture reseed, source change or new customer validation." + "sha256": "f0d498e843f3378ca57c491ef2963b28fa3f384141f62e11be9c46146bacc417", + "captured_at_utc": "2026-10-14T15:58:21Z", + "viewport": "1280x960", + "browser": "Google Chrome 148.0.7778.178", + "source_commit": "df8d804842425bdcf92c4b8eb5df8004314420c6", + "caption": "Exact before-and-after Preview of Regular & Sale prices (including variations).", + "visible_ui_text": "Set sale prices to $19.00 USD · 3 products (2 variations)\nPrice to change: Sale price. The regular price is the sale baseline and is preserved.\nSale price before to after\nHarbor Tee — Small\n$22.00 USD → $19.00 USD\nHarbor Tee — Large\n$26.00 USD → $19.00 USD" }, { "filename": "screenshot-3.png", "width": 1280, - "height": 900, + "height": 960, "format": "PNG", - "sha256": "a12d8a9a0e2413d3c54c75f66194fc6eef68e44e91d2e6e1152d39b343a8227b", - "captured_at_utc": "2026-10-05T22:53:47.382416Z", - "real_state": "Large-job progress and pagination", - "caption": "Background-job example with 24 products: see changed and remaining products, and Resume interrupted work. This capture predates live progress updates.", - "visible_ui_text": "WriteLeash Bulk Prices\nProgress and results\nA large job shows what is done, what remains and what needs attention, page by page.\nchanged · already at the target price · skipped · conflicts · remaining\nPrevious page\nNext page", - "captured_product_base": "a5a736b9d77308afd7534f23e7950b064aea767a" + "sha256": "93dad52dc9a9ae8ddb4663bb341deca54a149cf0a037a1d1d86a32870da014eb", + "captured_at_utc": "2026-10-14T15:58:21Z", + "viewport": "1280x960", + "browser": "Google Chrome 148.0.7778.178", + "source_commit": "df8d804842425bdcf92c4b8eb5df8004314420c6", + "caption": "Live background job progress with Resume.", + "visible_ui_text": "Progress and results\nWaiting to continue\nAutomatic updates active\nResume remaining products\nApply progress" }, { "filename": "screenshot-4.png", - "width": 1238, - "height": 1600, + "width": 1280, + "height": 960, "format": "PNG", - "sha256": "a5ebbd44629931c4788ee4624a0b96dfb233b54b9c6bff448655a1cfe1175e37", - "captured_at_utc": "2026-10-07T04:28:55.750290+00:00", - "real_state": "Real prepared local #188 Woo Admin fixture; minimal static capture for #195", - "caption": "Review completed changes and explained skips; one invalid price does not stop the useful result.", - "visible_ui_text": "Progress and results\nDecrease regular prices by 10% · 5 products (2 variations)\nFinished\nPlanned 5 products: 4 changed · 1 skipped.\nImported damaged price\nSkipped at preview\nThe stored price is outside the supported decimal contract.\nClean ceramic mug\nChanged\nUndo available for prices changed by this job.", - "captured_product_base": "2e059cacf46977cc3ae1eba15eba628ad6e7570e", - "capture_job_id": "8368c469-9bbd-4974-a160-5b7d28550306", - "capture_scope": "Existing synthetic Mixed catalog; no fixture reseed, source change or new customer validation.", - "crop": { - "x": 0, - "y": 0, - "width": 1238, - "height": 1600 - }, - "source_canvas": { - "width": 1238, - "height": 1632 - } + "sha256": "0947f52432cc673cc103cc69d54af84aeba42f82cf9c292debdc142d0efa59d2", + "captured_at_utc": "2026-10-14T15:59:17Z", + "viewport": "1280x960", + "browser": "Google Chrome 148.0.7778.178", + "source_commit": "df8d804842425bdcf92c4b8eb5df8004314420c6", + "caption": "Conflict protection: newer price is kept instead of overwritten.", + "visible_ui_text": "Cedar Field Jacket\nRegular price expected $100.00 USD\nRegular price now $120.00 USD\nRegular price planned $80.00 USD\nNewer price kept\nWriteLeash left the newer value unchanged." }, { "filename": "screenshot-5.png", - "width": 1240, - "height": 480, + "width": 1280, + "height": 960, "format": "PNG", - "sha256": "5181b4fba8643483cc0b57c2ebeffe4eba61c69ed278b6efd91d2b6d8dd9f956", - "captured_at_utc": null, - "real_state": "Real Regular Price conflict row and two completed rows from retained #170 Chromium capture", - "caption": "A later price or setting change becomes a conflict instead of a blind overwrite. Regular Price example: expected $100, planned $80, current $120 remains unchanged.", - "visible_ui_text": "Product\tExpected\tCurrent\tPlanned\tApply\tUndo\n$100.00 USD\t$120.00 USD\t$80.00 USD\tNot changed\nThis product’s price or other conditions changed after you reviewed the preview. WriteLeash left the newer value unchanged.\nChanged", - "captured_product_base": "bd66a79", - "source_capture": "docs/review/170/170-chromium-apply-conflict.png", - "source_sha256": "ed331d74a07afdaa88bbdff10084f2fc07ac0768703d581c2e1932c284686a24", - "crop": { - "x": 180, - "y": 1055, - "width": 1240, - "height": 480 - }, - "capture_date_note": "Retained #170 capture; original timestamp not recorded in its proof. No new capture." + "sha256": "082e583bb7c1af6605f45af5e00deda7c040b175225bab56dde1ad7910426a33", + "captured_at_utc": "2026-10-14T15:59:30Z", + "viewport": "1280x960", + "browser": "Google Chrome 148.0.7778.178", + "source_commit": "df8d804842425bdcf92c4b8eb5df8004314420c6", + "caption": "History + eligible Undo within 30 days.", + "visible_ui_text": "History\nUndo available for prices changed by this job.\nUntil November 13, 2026 3:59 pm (+00:00)\nOutcomes: 1 changed." }, { "filename": "screenshot-6.png", "width": 1280, - "height": 900, + "height": 960, "format": "PNG", - "sha256": "df7c40f4552bd8f9511e5c9320756fa5efba30cc834a0665bba78c476428d767", - "captured_at_utc": "2026-10-05T22:53:47.382416Z", - "real_state": "History and Undo availability", - "caption": "Review History outcomes and eligible Undo availability in this earlier example. Availability does not guarantee that every product will restore.", - "visible_ui_text": "WriteLeash Bulk Prices\nHistory\nTask / operator / time\tOutcome\tUndo\tAction\nUndo available for prices changed by this job.\nUntil ", - "captured_product_base": "a5a736b9d77308afd7534f23e7950b064aea767a" + "sha256": "24e8cf161074df8e0a2cabf90c5c57af9d83f4c698e29e3dac9bae41dca48a71", + "captured_at_utc": "2026-10-14T15:58:00Z", + "viewport": "1280x960", + "browser": "Google Chrome 148.0.7778.178", + "source_commit": "df8d804842425bdcf92c4b8eb5df8004314420c6", + "caption": "Safety limits: max products, max % increase/decrease, block zero prices.", + "visible_ui_text": "Safety limits\nMaximum changing products (0-1000)\n1000\nMaximum increase percent\n50\nMaximum decrease percent\n50\nBlock a preview that sets any changing price to zero" } ], "independent_price_observations": [ diff --git a/wordpress/tests/release/asset-audit-cases.php b/wordpress/tests/release/asset-audit-cases.php index 96815355..0432e526 100644 --- a/wordpress/tests/release/asset-audit-cases.php +++ b/wordpress/tests/release/asset-audit-cases.php @@ -31,7 +31,7 @@ $change_conflict_text = static function ( string $f, callable $change ): void { $p = $f . '/wordpress/release/assets-122/proof.json'; $proof = json_decode( file_get_contents( $p ), true, 512, JSON_THROW_ON_ERROR ); - $proof['screenshots'][4]['visible_ui_text'] = $change( $proof['screenshots'][4]['visible_ui_text'] ); + $proof['screenshots'][3]['visible_ui_text'] = $change( $proof['screenshots'][3]['visible_ui_text'] ); file_put_contents( $p, json_encode( $proof, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE ) ); }; $cases = array( @@ -45,8 +45,8 @@ 'missing required icon / SVG fallback' => static function ( $f ) { unlink( $f . '/wordpress/assets/icon-128x128.png' ); }, 'wrong exact icon dimensions' => static function ( $f ) { copy( $f . '/wordpress/assets/icon-128x128.png', $f . '/wordpress/assets/icon-256x256.png' ); }, 'screenshot numbering gap' => static function ( $f ) { rename( $f . '/wordpress/assets/screenshot-3.png', $f . '/wordpress/assets/screenshot-7.png' ); }, - 'readme caption count mismatch' => static function ( $f ) { $p = $f . '/wordpress/writeleash/readme.txt'; file_put_contents( $p, preg_replace( '/^6\. Review History.*\n/m', '', file_get_contents( $p ) ) ); }, - 'readme caption content mismatch' => static function ( $f ) { $p = $f . '/wordpress/writeleash/readme.txt'; file_put_contents( $p, str_replace( 'Review exact before-and-after', 'Review different', file_get_contents( $p ) ) ); }, + 'readme caption count mismatch' => static function ( $f ) { $p = $f . '/wordpress/writeleash/readme.txt'; file_put_contents( $p, preg_replace( '/^6\. Safety limits.*\n/m', '', file_get_contents( $p ) ) ); }, + 'readme caption content mismatch' => static function ( $f ) { $p = $f . '/wordpress/writeleash/readme.txt'; file_put_contents( $p, str_replace( 'Exact before-and-after Preview', 'Review different', file_get_contents( $p ) ) ); }, 'SVG outside supported icon role' => static function ( $f ) { copy( $f . '/wordpress/assets/icon.svg', $f . '/wordpress/assets/banner.svg' ); }, 'active SVG content' => static function ( $f ) { $p = $f . '/wordpress/assets/icon.svg'; file_put_contents( $p, str_replace( '', '', file_get_contents( $p ) ) ); }, 'unexpected large binary' => static function ( $f ) { file_put_contents( $f . '/wordpress/assets/banner-772x250.png', str_repeat( 'x', 2 * 1024 * 1024 + 1 ), FILE_APPEND ); }, diff --git a/wordpress/writeleash/readme.txt b/wordpress/writeleash/readme.txt index e66231db..b10a6c4d 100644 --- a/wordpress/writeleash/readme.txt +++ b/wordpress/writeleash/readme.txt @@ -128,14 +128,13 @@ effects. == Screenshots == -1. Earlier selection-screen example: choose products by name, SKU or category. Current category selection also offers nested subcategories. -2. Review exact before-and-after Sale Price values, variations, warnings and skips in this earlier Preview example. -3. Background-job example with 24 products: see changed and remaining products, and Resume interrupted work. This capture predates live progress updates. -4. Review completed changes and explained skips; one invalid price does not stop the useful result. -5. A later price or setting change becomes a conflict instead of a blind overwrite. Regular Price example: expected $100, planned $80, current $120 remains unchanged. -6. Review History outcomes and eligible Undo availability in this earlier example. Availability does not guarantee that every product will restore. - -Earlier authentic captures; current labels and controls may differ. +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. + Not all features are pictured. == Frequently Asked Questions == @@ -148,7 +147,8 @@ Regular Price; regular targets must remain above an existing sale. = What happens if a price changes after Preview? = Target-price, product/parent eligibility, currency and precision checks can -refuse a change. Review conflicts in a fresh Preview with separate approval. +refuse a change. A later price or setting change becomes a conflict instead of a blind overwrite. +Review conflicts in a fresh Preview with separate approval. Checks compare current values: changes away and back may not be detected. = Can I review the Preview without changing prices? =