| @@ -130,8 +130,23 @@ | ||
| 130 | 130 | * live to recompute it from — the honest form is a constant a human bumps in the same commit |
| 131 | 131 | * that changes the shape. Deliberately NOT an option or a filter: nobody but us can change what |
| 132 | 132 | * we serve (see the constants-not-env-vars rule in the repo's agent context). |
| 133 | 133 | * |
| 134 | + * # Skipped-release caveat for the collections #1756 phase 1 added | |
| 135 | + * | |
| 136 | + * A client cold-adopts a fingerprint key it has never stored, so a contract bump for one of | |
| 137 | + * the six phase-1 collections only reaches tills whose server passed through a release that | |
| 138 | + * served the key at the OLD version first — a server upgrade that skips straight past phase 1 | |
| 139 | + * cold-adopts at the new version with no re-pull. Between phase 1 and the 1.11.0 protocol | |
| 140 | + * gate this is moot (recipe changes are batched AT the gate, whose forced resync covers | |
| 141 | + * them); if a pre-gate bump for one of the six is ever needed, it needs a first-seen | |
| 142 | + * migration protocol first (#1756 phase 2/3 territory — see the issue). | |
| 143 | + * | |
| 144 | + * ADR 0036 extends that rule to ANY collection serving-recipe change: serializer shape, digest | |
| 145 | + * formula key sets (DIGESTED_META_KEYS / CUSTOMER_DIGESTED_META_KEYS in Digest_Index), or the | |
| 146 | + * augmentation set. Bump that collection's version IN THE SAME COMMIT; the fingerprint move is | |
| 147 | + * what triggers the client re-pull that a silent formula change never did. | |
| 148 | + * | |
| 134 | 149 | * # Safety against an un-upgraded store |
| 135 | 150 | * |
| 136 | 151 | * A store still on the old plugin never moves this value, so its clients see no change and |
| 137 | 152 | * re-fetch nothing. That is what lets the migration ship with no version gate and no bespoke |
| @@ -147,13 +162,28 @@ | ||
| 147 | 162 | */ |
| 148 | 163 | private const BASELINE_CONTRACT_VERSION = 1; |
| 149 | 164 | |
| 150 | 165 | private const PAYLOAD_CONTRACT_VERSION = array( |
| 166 | + // products: product serialization + DIGESTED_META_KEYS formula + barcode augmentation. | |
| 167 | + 'products' => 1, | |
| 151 | 168 | // 2 (1.10.1): variations are serialized through WC_REST_Product_Variations_Controller |
| 152 | 169 | // instead of the products controller — singular `image`, `wc_get_formatted_variation()` |
| 153 | 170 | // `name`, and no product-only fields. See the 1.10.1 variations spec, S1/S6. |
| 171 | + // variations: variation serialization + shared DIGESTED_META_KEYS formula + barcode augmentation. | |
| 154 | 172 | 'variations' => 2, |
| 155 | - 'products' => 1, | |
| 173 | + // orders: order serialization + the HPOS/CPT order digest formula. | |
| 174 | + 'orders' => 1, | |
| 175 | + // customers: customer serialization + CUSTOMER_DIGESTED_META_KEYS formula. | |
| 176 | + 'customers' => 1, | |
| 177 | + // categories: product-category term serialization + its augmentation set. | |
| 178 | + 'categories' => 1, | |
| 179 | + // brands: product-brand term serialization + its augmentation set. | |
| 180 | + 'brands' => 1, | |
| 181 | + // tags: product-tag term serialization + its augmentation set. | |
| 182 | + 'tags' => 1, | |
| 183 | + // coupons: coupon serialization + its augmentation set. | |
| 184 | + 'coupons' => 1, | |
| 185 | + // tax_rates: tax-rate serialization + its augmentation set. | |
| 156 | 186 | 'tax_rates' => 1, |
| 157 | 187 | ); |
| 158 | 188 | |
| 159 | 189 | /** |
| @@ -272,11 +302,13 @@ | ||
| 272 | 302 | * |
| 273 | 303 | * Deletes by EXACT key over the known COLLECTIONS rather than a |
| 274 | 304 | * `LIKE 'woocommerce_pos_sync_config_fp_%'` scan: the namespace is a closed set, so the |
| 275 | 305 | * exact-key form needs no $wpdb query and cannot collide with a future option that |
| 276 | - * happens to share the prefix. Only the barcode collections were ever written, but | |
| 277 | - * sweeping the full COLLECTIONS set costs one extra no-op delete and catches a | |
| 278 | - * stray row from any revision. | |
| 306 | + * happens to share the prefix. Only the barcode collections were ever written, so | |
| 307 | + * sweeping the now-universal membership (nine collections since #1756) costs a | |
| 308 | + * handful of no-op deletes on a fresh install and nothing on an already-swept one | |
| 309 | + * (the CLEANUP_VERSION latch above), while catching a stray row from any revision | |
| 310 | + * that DID write one. | |
| 279 | 311 | * |
| 280 | 312 | * Idempotent and correctness-neutral: the endpoint recomputes the fingerprint from |
| 281 | 313 | * live options as the sole source of truth, so removing these rows cannot change a |
| 282 | 314 | * served value. |
| @@ -289,9 +321,12 @@ | ||
| 289 | 321 | foreach ( self::collections() as $collection ) { |
| 290 | 322 | delete_option( self::LEGACY_PROACTIVE_OPTION_PREFIX . $collection ); |
| 291 | 323 | } |
| 292 | 324 | |
| 293 | - update_option( self::CLEANUP_VERSION_OPTION, self::CLEANUP_VERSION, false ); | |
| 325 | + // Autoloaded: the Init constructor reads this latch on every request. | |
| 326 | + // Existing rows from older releases are flipped by | |
| 327 | + // Activator::autoload_request_latches() on upgrade. | |
| 328 | + update_option( self::CLEANUP_VERSION_OPTION, self::CLEANUP_VERSION, true ); | |
| 294 | 329 | } |
| 295 | 330 | |
| 296 | 331 | /** Collections whose served representation depends on the barcode setting. */ |
| 297 | 332 | /** |