'The Qty edit is posted and then discarded: the number typed is never read. Product decision at migration.', 'B2' => 'The export prints a different headline figure than the screen: two metrics under one label (126.30 vs 29.37 on live data).', 'B3' => 'The export is a superset of the screen and says so nowhere: 790 rows against 500.', 'B4' => 'The 500-row cap is silent. No "showing X of Y" anywhere on the queue.', 'B5' => 'Dismiss and the never-restock action only set opacity 0.4 and leave the row in place.', 'B6' => 'Never-restock is one-way. It writes a permanent blocklist and nothing in the UI can undo it.', 'B7' => 'Dead provenance branches: the parent_history and parent_sale pills are never emitted by the procedure.', 'B8' => 'Two tables in one file with incompatible contracts: different caps, paging, sorting, row identity. Convert as two registry rows.', 'B9' => 'Branch shape is hardcoded 4-wide with untranslated Greek literals in the template.', 'B10' => 'Vendor exports read the DOM, so a server-side table exports only the loaded page.', 'B11' => 'The t34 export WRITES: clicking Excel/CSV/Copy mutates desired_qty. Do not migrate t34 as a report.', 'B12' => 'String columns render unescaped, and six reports build anchor and image markup inside SQL with CONCAT.', 'B13' => 'The division-by-zero vendor patch is not applied on apollo, so an empty aggregate report still fatals there.', 'B14' => 't43 returns 0 rows and t18 returns 1. Neither exercises paging or filtering, so neither can validate a replacement.', 'B15' => 'Cascade and per-column filtering are a REQUIREMENT, not an option. Validated against the vendor byte for byte.', 'B31' => 'masterDetail is set on 9 tables but no renderer is on disk. Not owed until somebody confirms it renders on production.', 'B16' => 'Two of the three xlsx writers guess cell types with is_numeric(), coercing Greek postcodes and SKUs like 0012 into numbers.', 'B17' => 'Three parallel xlsx writers with different capabilities.', 'B18' => 'Participant names, emails and phones export behind nothing more than edit_posts: 35 non-admin accounts hold it.', 'B19' => 'The fulfilment export SQL is hand-copied into two functions, with a comment asking maintainers to keep them identical.', 'B20' => 'At least five exports are an import API. Localised headers or formatted values silently break the matching importer.', 'B53' => 'aieo_access is granted through edit_pages as well as manage_woocommerce, so 12 non-commerce accounts hold it.', 'B54' => 'Seven file-based exports land in publicly fetchable uploads directories, protected only by an empty index.html.', 'B55' => 'aieo_use_stock_scanner cannot be revoked: it is re-added to administrator and shop_manager on every admin load.', 'B21' => 'The cancellations pager drops the rl_kind filter from its query string, so paging silently widens the result set.', 'B22' => 'The withdrawal panel colspan is a hand-passed integer. A wrong value overhangs the table with no error.', 'B23' => 'Workflows table headers are hardcoded English in JS, never through __(). The table is untranslatable as built.', 'B24' => 'theme-compat sorts on rendered text, so em dashes, code chips and a CSS arrow all become part of the sort key.', 'B25' => 'aieo_consent_log has 47,115 rows and no reader anywhere. The proof-of-consent screen does not exist.', 'B26' => 'Silent row caps across the product: LIMIT 200, numberposts 200, a 20-page cap, none of them disclosed.', 'B27' => 'eshop_latest_transaction_date is NULL on every row. Blocked on which order statuses should count.', 'B33' => 'Four independent pagers and per-page controls, none shared.', 'B34' => 'One sentence, two msgids: the "showing X to Y of Z" string exists twice, both translated.', 'B56' => 'A declared-but-conditional action rendered an ACTIONS header over a column of empty cells.', 'B57' => 'Known-defect chips showed bare ids with no way to learn what they meant.', 'B58' => 'insights_t43 fatals on render with a DivisionByZeroError. B13 confirmed live on ffnew, not only on production.', 'B64' => 'A real export runs for minutes and nothing raised the PHP time limit, so a normal host would deliver a truncated file that opens cleanly.', 'B65' => 'aieo_core_product_vitals stores rendered HTML and absolute URLs, so link_to_view and image_url are wrong on every install except the one that wrote them.', 'B59' => 'Escaped ampersands in the inline script broke the whole of Tools > Data tables JavaScript: every control on it was dead.', 'B66' => 'The first/last-in-basket reports count single-product orders, where first and last are the same line, so 44% of their frequency mass contradicts AIEO_Basket_Role, which excludes them.', 'B67' => 'Over a third of the basket-position rows are products deleted from the catalogue, rendered as a blank line carrying a link to a page that no longer exists.', 'B68' => 'The Woo-to-ERP matcher returns "Not matched" for every order of the two live months while the historical table matched about 90%, and no month between them was reconciled at all.', 'B70' => 'The out-of-stock SQL hardcodes https://femme-fatale.gr into the Edit link on every row, so on any other install the button opens production.', 'B71' => 'The only footer on the out-of-stock report sums items-per-day across 1,824 products and labels the result "Loss Estimate", beside columns denominated in euros.', 'B72' => 'Overlapping tone bands resolved to the LAST declared one, so a stock of -324 rendered in the tone meant for zero on a shipped report.', 'B69' => 'Both invoice-matching reports HIDE report_month, so nothing on either screen says which month it is showing, and their source tables are rebuilt as the month turns.', 'B73' => 'Three screens build a data grid inside a JS string, which libxml hoisted out of the script, so the census counted tables nobody rendered and gave each a label from another card.', 'B74' => 'The surveys rescue and referral lists hardcoded a euro sign on LTV, so the figure was wrong on any install whose store currency is not the euro.', 'B75' => 'Both sentiment-drift change columns were coloured by the COMBINED swing, so an NPS fall of four rendered green whenever satisfaction rose further.', 'B76' => 'A column declaring a literal suffix such as a percent sign rendered nothing: the resolver read row keys only, so two shipped ratings bars lost their sign silently.', 'B79' => 'The filter dropdowns never narrowed as you typed: the transport read the search term from the wrong key, so every list came back whole - 195 brands, unfiltered.', 'B78' => 'A column href, suffix or subline naming a row field whose name is also a global function had the resolver CALL that function: edit_link() wp_died the whole screen on a capability check.', 'B77' => 'Multiselect filters rendered as bare listboxes whose options load on focus, so three category filters sat empty on screen while the columns behind them held 12, 70 and 162 values.', 'B35' => 'A TOTAL row written into the
is carried along by the client sorter and lands in the middle of the data; a totals row has to be a real .', 'B80' => 'An Edit handler rebuilt its record from the RENDERED cells, splitting one on a colon and testing another against a star glyph, so a formatting change could corrupt what was saved.', 'B81' => 'A table assembled in a JS string carries hardcoded English headers that never reach the catalogue, so it renders untranslated on every Greek install and no census or assertion can see it.', 'B82' => 'Action labels, badge label maps and header tooltips were the source strings a definition stores and render never resolved, so they read English beside Greek headers.', 'B83' => 'A hand-rolled pager printed twenty numbered links and stopped, with no next and no last, so at 50 rows a page everything past row 1,000 was unreachable.', 'B84' => 'A GMT timestamp was printed as the stored string with " UTC" appended instead of being converted, leaving the reader to do the arithmetic on a screen where every other date is the shop clock.', 'B85' => 'A sort-header closure built its URL into a variable it never imported, so every header on the meta-batch screen rendered with an empty href and no column there has ever sorted.', 'B86' => 'An action data-* literal that shares its name with a column resolves to that ROW\'S value first, so a button carrying data what=description posted nothing on every row whose description was empty.', 'B87' => 'Clear filters and Apply sent no scope parameters, so the server filled in each default and the table came back showing thirty days while the screen\'s own dropdown still said ninety.', );