*** DT-PM AI Sale Assistant for WooCommerce Changelog ***

2026-10-25 - version 1.4.1
Requires Kern-API >= commit 1dfcb9a (unchanged from 1.4.0) - documentation/translation-only release, prompted by DT-136 (Infrastruktur, 25.10.2026): the readme shipped with 1.4.0 on the dt-pm.eu channel still only described the product-advice features and did not disclose the external-service data flows the Service Agent features (order lookup, handover, policy sync, MCP Bridge) added - dt-pm.eu already has 1.4.0 live with the old readme text, so this correction ships as 1.4.1 rather than editing the already-published 1.4.0 package.
* Changed - readme.txt "Main features" now lists the Service Agent features added in 1.4.0; "External services" gained four new disclosure points (order data sent for order questions, policy page text synced on save/daily, handover email sent directly by the store's own WordPress installation rather than through our service, and what an MCP Bridge key can read/change).
* Changed - corrected the 1.4.0 changelog entries below for "Service Assistant Policies", "Shipment Tracking", and "MCP Bridge": they said "section in Settings" at the time of writing, but by release (commit `4aa1e8e`) all three had moved into their own "Service Agent" tab.
* Added - the three German translations ("Service Agent" and its two Help-tab paragraphs) that were still missing from the bundled German/Austrian/Swiss translation files in 1.4.0 (only the `.pot` template had them).

2026-10-25 - version 1.4.0
Requires Kern-API >= commit 1dfcb9a - this version calls several new Kern-API endpoints, among them `POST /chat/turn` (replaces `POST /agent/turn` as the widget's main message endpoint, routing each message to an advice or a service agent), `POST /agent/continue-with-bestellhistorie`, `POST /agent/continue-with-uebergabe`, `POST /agent/uebergabe-autorisieren`, `POST /agent/uebergabe-fehlgeschlagen`, and `GET /tenants/byok-modelle`; an older Kern-API without these would reject or silently ignore the new capabilities below.
* Added - the assistant can now check a logged-in customer's own order history (their last 5 orders) to answer "same as last time, but in green"-style follow-up questions directly, instead of asking for an order number it has no way to resolve on its own.
* Added - the assistant can now also look up one specific order by its order number when a logged-in customer asks about it in the chat (status, items, shipping method, tracking). No guest/email path exists for this - only a logged-in customer's own orders are ever returned.
* Added - a new, fourth tool the assistant can use mid-conversation: when it can't help further, it drafts a short summary of the customer's issue and shows it before sending anything. The customer can edit the summary, sees that it will go by email to the store's own support contact, and must click "Yes, send" (or "No, not now") - nothing is sent without that explicit step. A logged-in customer's account email/phone are used automatically; a guest is asked for an email (required) and phone (optional) first. A failed send shows an honest error plus the existing fixed contact link.
* Security - an independent review of the handover feature above, done before this release, found two real gaps and both are fixed: (1) the AJAX endpoint that actually sends the email had no way to verify that a genuine assistant-initiated handover ever took place for the given conversation - the Kern-API now has to confirm this server-side before the plugin is allowed to send. (2) the "only one handover per conversation" limit was enforced only in the browser (a new tab or cleared site data could bypass it) - the Kern-API now enforces this itself as well, while still allowing a retry if the actual email send fails (a failed attempt never counts against the limit, per existing policy). Also added a length cap on the summary and phone number fields before they reach the email.
* Added - a new "Service Assistant Policies" section in the Service Agent tab: five page pickers (Shipping, Returns, Withdrawal, Payment, FAQ) where you assign existing pages on your site; their text is synced to the Kern-API automatically whenever you save, and again once daily, so the assistant can answer policy questions from your own wording instead of guessing. Unassigning a page (back to "— Not configured —") removes that policy's text server-side instead of leaving it stale.
* Added - a new "Shipment Tracking" section in the Service Agent tab: the assistant automatically checks the official WooCommerce Shipment Tracking extension's data first; if your shipping plugin stores tracking numbers under a different meta key, you can enter that key here as a fallback. An order with several packages now reports every tracking number it has, not just the first one.
* Added - a model-selection dropdown now appears under each provider's API key field (Anthropic, Mistral, OpenAI) once you bring your own key, letting you pick a specific, DT-curated model instead of always getting our platform default - the same choice also applies to the assistant's internal advice/service classification step.
* Added - bringing your own API key (BYOK) is no longer restricted to paid plans; the free tier's usage limit is now enforced independently of whether you use our platform key or your own.
* Fixed - OpenAI had no API key field in Settings at all (only Anthropic and Mistral did), and separately, any OpenAI key entered through another path would always fail verification because it was being checked against Anthropic's API instead of OpenAI's. OpenAI now has its own key field next to the other two providers, and verification checks the right provider.
* Added - a new "MCP Bridge" section in the Service Agent tab lets you generate a key (shown once, in plain text, at creation time only) so an MCP-capable AI client such as Claude can read and change these settings on your behalf as a Bearer token; revoking it immediately invalidates that key.
* Fixed - the hourly catalog availability sync (`admin/availability-sync.php`) deduplicated products by parent-product ID - two genuinely different product groups that happened to share the same parent-product ID (a pre-existing catalog data quirk, not caused by this plugin) were silently merged into a single row, and the second group's SKU/availability disappeared from the sync payload without any visible error. Deduplication now uses SKU instead, so both are kept and reported correctly.

2026-10-14 - version 1.3.0
Requires Kern-API >= commit 9a769d8 - this version tracks a server-issued conversation identifier (`konversation_id`) across turns, shows the new mandatory AVV-consent checkbox/catch-up banner, and uses a new non-destructive category-save endpoint; an older Kern-API without `GET /avv/aktuelle-fassung`, `POST /tenants/{tenant_id}/avv-zustimmung`, `POST /categories/aenderungen-speichern`, or the `konversation_id` handling in `POST /agent/turn`/`POST /agent/continue-with-live-data` would reject or silently ignore these calls.
* Added - the chat widget now tracks a server-issued conversation identifier across turns, so a back-and-forth of up to 20 customer messages counts as a single billable conversation (matching the Kern-API's new billing unit) instead of billing every message separately. A timing bug found during testing - a follow-up question right after the assistant looked up live prices/availability could otherwise have been miscounted as a brand-new conversation - was caught and fixed before this ever reached a release.
* Added - "Connect this store" now requires checking a box that links to the current AVV (data processing agreement) version before the button becomes clickable. An already-connected store that hasn't yet agreed to the current AVV version sees a dismissible banner in the dashboard instead, prompting it to catch up - the chat widget keeps working normally in the meantime.
* Added - the Category Analysis page's "Save" button now reads "Save changes" and uses a new, non-destructive save path once you're editing an already-confirmed grouping (renaming a group, moving a category between groups, adding or removing one) - causal chains and already-processed product coverage for unchanged or renamed groups are kept instead of being rebuilt from scratch. Removing a group still shows a confirmation listing exactly what goes with it (causal chain, processed products, and more) before saving. The original "Save" (full replace, for "Analyze again") is unchanged.
* Changed - the explanation of "Standalone variant" vs. "Order option only" (which decides whether a product variant gets advised on individually) is now also shown once, visibly, above the variant-attribute table on the Product Coverage page, in addition to the existing per-row tooltip.
* Changed - the free-tier catalog-limit message for a product still waiting in the background queue no longer implies your *current* plan is the one limiting it, which could read as misleading after an upgrade.

2026-10-10 - version 1.2.0
Requires Kern-API >= commit a2995ac - the plugin now requests a short-lived Storefront-Token (`POST /tenants/{tenant_id}/storefront-token`) instead of sending the permanent tenant secret directly from the browser; an older Kern-API without this endpoint would reject every browser request once the plugin stops also offering the secret, so this is a hard requirement starting with this version.
* Changed - the chat widget no longer embeds the store's permanent secret into the page source sent to every visitor's browser. It now fetches a short-lived Storefront-Token (valid 15 minutes) through the plugin's own server right when the widget loads - the permanent secret itself never leaves the server. The token is requested through a standard AJAX call, which store-caching plugins and CDNs never cache, so a cached page can never serve a stale token. If a request still gets rejected (e.g. a browser tab left open for a long time), the widget automatically fetches a fresh token and retries once, with no visible interruption to an ongoing conversation and no error shown beyond the assistant's existing "something went wrong" message if that retry fails too.
* Added - right after updating to this version, the plugin replaces its stored secret with a freshly issued one on its next wp-admin page load (silently, in the background) - the old secret, which had been visible in the page source until now, stops working from that moment on. Downgrading to an older plugin version afterwards still works normally, using the new secret value.

2026-10-10 - version 1.1.3
Requires Kern-API >= commit 3c31fd7 (unchanged from 1.1.2) - this is a pure frontend/JS fix, no Kern-API dependency.
* Fixed - `admin/js/causal-chain.js` and `admin/js/content.js` loaded their subcategory list exactly once, at page load (`DOMContentLoaded`) - a purely client-side tab switch (`admin/js/tabs.js`) never triggered a re-fetch. After confirming a Category Analysis and switching to the Causal Chains tab without reloading the page (or, equally, after confirming a Causal Chain and switching to Product Coverage), the newly confirmed subcategory still showed as "not done yet" until the page was reloaded. `tabs.js` now dispatches a `ki-berater-tab-activated` custom event whenever a tab is actually clicked, which both feature scripts listen for on their own panel to refresh their state - kept the two scripts decoupled (no direct cross-file calls, consistent with the existing "duplicated, not imported" convention). Also fixed a related, previously latent bug this exposed: `causal-chain.js`'s loader never explicitly reset its "no subcategories yet" hint/picker visibility back to normal once shown, relying on a one-time page load always starting from the correct default HTML state - harmless as long as it only ran once, but would have left the hint stuck visible forever on any later successful re-fetch. Also preserves the currently selected subcategory across a re-fetch in both tabs (previously, re-running the loader would have silently reset an in-progress selection back to the placeholder).

2026-10-10 - version 1.1.2
Requires Kern-API >= commit 3c31fd7 (unchanged from 1.1.1) - this fix calls only the already-existing `GET /variation-attributes` endpoint, no new Kern-API dependency.
* Fixed - the hourly catch-up cron for incomplete product processing (`admin/content-processing-resume.php`) used a different, simpler product-fetching routine (`ki_berater_fetch_sample_products()`) than the one the browser's "Process remaining" button uses (`ki_berater_fetch_content_products_for_category()`/`ki_berater_expand_variable_product_for_content()`) - for a variable product with at least one merchant-confirmed relevant distinguishing attribute (e.g. color), the cron reported only a single row using the parent product's own (often empty) SKU/price, instead of one row per actual relevant variant combination with that variant's own SKU/price. The cron now fetches the merchant's confirmed relevant attributes itself (`GET /variation-attributes`) and uses the same variant-aware logic as the browser path; deduplication switched from `vaterprodukt_id` to `sku` accordingly, since a variant-expanded product can now report multiple distinct SKUs.

2026-10-08 - version 1.1.1
Requires Kern-API >= commit 3c31fd7 - an older Kern-API simply ignores the new `vollstaendiger_katalog` field this version adds to its "process subcategory" request (safe, additive field, see CLAUDE.md "Kern-API-Antwortfelder nur hinzufügen"), but without it the orphan-cleanup fix below has no effect server-side.
* Fixed - an automatic catch-up run for a handful of still-missing products (the hourly background check in `admin/content-processing-resume.php`, or clicking "Process remaining" right after a few products failed to process) sent only that handful of products to the Kern-API, which then mistook the partial list for the subcategory's complete current catalog and deleted every other, already-processed product's recommendation data - real production incident, found and fixed together with the matching Kern-API-side change (see Kern-API changelog). The plugin now tells the Kern-API explicitly whether a given processing request carries the full catalog ("Reprocess everything"/"Force") or only a partial list ("Process remaining", the hourly catch-up) - only a full-catalog request may trigger cleanup.
* Fixed - the chat widget's product name (14px -> 15px), price (13px -> 17px), panel title (15px -> 14px) and footer text (12px -> 11px) now match the intended design sizes - the price in particular was noticeably smaller than intended.
* Changed - the short "thinking trace" line during a search now shows only the current step, replacing the previous one as the agent moves through them, and disappears entirely once the answer arrives - previously it stayed visible afterwards as a summary of every step, which could show the same step twice if the agent needed a second round of live price/availability data for the same customer question.
* Fixed - a rare layout glitch where the chat widget's header could scroll out of view mid-conversation, leaving empty space at the bottom of the panel - the "scroll to the start of a new answer" behavior could, in specific timing conditions, scroll the whole widget panel instead of just its message list; now scrolls only the message list, which cannot affect the panel itself.
* Fixed - several backoffice screens (status/plan, settings, catalog diagnosis, product coverage, causal chains, and the plugin's own name/description/author as shown on its WordPress.org listing) had untranslated text in the bundled German translations - the plugin's own translation-source file had fallen behind the actual on-screen text and was missing an entire screen (the status/plan page) outright. Also made the informal ("du") vs. formal ("Sie") address consistent throughout each translation file (previously mixed within the same file - a formal-address shop could suddenly see an informal sentence, or the reverse), corrected two translation errors and several missing umlauts, and brought the Austrian/Swiss German translations in line with the (now consistently informal) German one - Swiss German also uses "ss" instead of "ß" throughout, as before.

2026-10-07 - version 1.1.0
Requires Kern-API >= commit 06b1350 (current production state at release time) - older plugin versions keep working against this Kern-API, but the "In stock" label, the real search-hit count, and the "What I understood" box need this Kern-API version to actually show (both fields are purely additive, an older plugin simply ignores them).
* Added - the chat widget's whole look now matches the current mockup: colors/corner radius/font are derived from the shop's own theme, with a guaranteed readable contrast (text/borders on a light background keep at least 4.5:1/3:1 against the surrounding area) and corner rounding that scales with the theme but never grows past what a single line of text needs, even if a chip wraps to two or three lines. A short "thinking trace" line stays visible after a search, summarizing what actually happened in that turn.
* Added - a recommended product card now states "In stock" (the shop's own live stock check already guarantees this before the card is ever shown). The thinking-trace line names the real number of matching products a search found, and a short box above the recommendation shows which of the customer's own stated preferences (specific traits, price range) the assistant picked up on - both using only data the assistant already had, nothing invented.
* Added - the widget now derives its color/corner-radius/font from whichever source actually has something usable on the current page: a real button element first, then the theme's own WordPress "Global Styles" settings, then a generic page element, and only then a fixed default - instead of only the product page's own "Add to cart" button (which doesn't exist on the homepage, cart, or a blog post). Once found, the choice is kept for the rest of the visit so the widget doesn't change look between pages.
* Changed - the widget's own title now defaults to the English "Start assistant" instead of a hardcoded German phrase; a merchant who hasn't set their own title now sees the plugin's own translated default in their store's language, not always the old German text regardless of language.
* Fixed - proactively suggested starter questions are now generated with an explicit target length so they read as one short, concrete question instead of a long customer message with backstory, and fit on at most two lines on both desktop and mobile widths; the widget also caps the visible chip at two lines as a safety net (the full question is still used when a shopper clicks it, never the shortened display text).
* Fixed - the plugin's own `KI_BERATER_VERSION` constant (used to cache-bust the widget's CSS/JS on every update) had fallen out of sync with the version number in the plugin header, which could make a visitor's browser keep serving an old, cached version of the widget's styling/script after an update - kept in sync with the header again from this version on.

2026-10-01 - version 1.0.14
* Changed - `screenshot-8.png` replaced with an updated capture showing an actual conversation in the chat widget (budget/taste follow-up question, then a matching product recommendation with an "Add to cart" button) - previously only showed the closed chat button on a product listing. Caption updated to match (set directly in the WordPress.org SVN assets repo by Infrastructure, SVN revision 3723768, now mirrored here).
* Changed - `== External services ==` point 5 now also lists the store's configured language (`seiten_sprache`) among the data sent with each shopper chat message - this has been sent since 1.0.9 (language-matching fix) but was missed in the readme at the time, flagged by Infrastructure's WordPress.org submission review.

2026-10-01 - version 1.0.13
* Fixed - `readme.txt`'s `== Screenshots ==` section still carried only three outdated captions from a much earlier, smaller screenshot set (the files on the actual WordPress.org listing had since grown to eight, through several unrelated updates, without ever updating this section) - no longer matching the files in order or count. Replaced with eight captions (connection/purchase, AI model/support/widget settings, tone of voice, category analysis, causal chain coverage check, causal chain decision model, open chat widget, closed chat button) matching `screenshot-1.png` through `screenshot-8.png` 1:1. Also renamed the staged screenshot files themselves from an inconsistent `screenshot-1a.png`/`screenshot-1b.png`/`screenshot-chat-1.png`/`screenshot-chat-2.png` scheme to the required plain numeric `screenshot-<N>.png` scheme WordPress.org expects (content unchanged, verified image-by-image against Dirk's proposed caption order).

2026-10-01 - version 1.0.12
* Changed - refreshed the WordPress.org/WooCommerce.com store banner artwork (`admin/assets/banner-source.svg`, `banner-1544x500.png`, `banner-772x250.png`) - the "DT-PM AI Sale Assistant" title lettering is now larger and more legible, icon artwork unchanged. The same adjustment (title font-size 42px -> 46px) was applied to the separate, narrower banner shown at the top of every plugin admin page (`admin/assets/banner-dashboard.svg`) for visual consistency, even though that file does not share markup with the store banner.

2026-10-01 - version 1.0.11
* Added - "Switch to dt-pm.eu" button in the Status tab's "Your Plan" card for stores activated via a WooCommerce Marketplace contract number (`POST /tenants/{id}/kanalwechsel-zu-dtpm`) - re-reads the current subscription from the WooCommerce Billing API, computes the remaining days in the current billing period, and requests a one-time, time-limited voucher from a new internal dt-pm.eu endpoint (HMAC-SHA256 signed) covering that remaining time, shown inline as a code and redemption link. The actual channel switch in our records still only happens later, when the merchant enters the new dt-pm.eu license key received after redeeming the voucher - this button only requests the voucher.
* Fixed - entering a dt-pm.eu license key for a store already activated via a WooCommerce Marketplace contract number is now rejected by default, closing a gap where this could silently switch the store's purchase channel away from the Marketplace without any deliberate action. It is only accepted immediately after using the new "Switch to dt-pm.eu" button above (a short-lived, one-time authorization, matching the voucher's own validity window) - this is now the one deliberate way to switch, with no cheaper side path. If a channel switch happens, a dismissible notice appears in the Status tab confirming it ("Your account now runs via dt-pm.eu instead of the WooCommerce Marketplace").

2026-10-01 - version 1.0.10
* Added - "Cancel subscription" button in the Status tab's "Your Plan" card, next to "Upgrade plan" - only shown while a paid subscription is actually active. Stores activated via a WooCommerce Marketplace contract number cancel through a new Kern-API endpoint (`POST /tenants/{id}/abo-kuendigen`) that calls `DELETE /subscriptions/{contractID}` against the WooCommerce Billing API (sandbox/production via the existing `WOOCOMMERCE_BILLING_API_ENV` switch); stores activated via a dt-pm.eu license key are linked out to the existing cancellation option in their dt-pm.eu customer account (new `DTPM_KUENDIGEN_URL` environment variable, falls back to the dt-pm.eu homepage) - neither path is new functionality on dt-pm.eu's side, just a new entry point in the plugin. A cancellation takes effect at the end of the already paid period (same behavior on both channels); the plugin does not change the tier/subscription status itself when cancelling - that still happens, as before, only once WooCommerce's `saas_billing_contract.prepaid_term_ended` webhook event actually arrives at the end of the term. A confirmation prompt is shown before cancelling, and the result is shown inline on the Status page.

2026-10-01 - version 1.0.9
* Fixed - BEFUND-antwortsprache-deutsch-trotz-englischer-widget-sprache.md - the first reply of a conversation (e.g. right after clicking a suggested starter question, before any free-text message exists) could come back in German even when the store's language was set to something else, because the assistant had no signal at all about the store's configured language and fell back to whatever language dominated the mostly-German system prompt/causal-chain content. The chat widget now sends the store's WordPress language code (`get_locale()`) as `seiten_sprache` with every `POST /agent/turn`/`POST /agent/continue-with-live-data` request (`dtpm-ai-sale-assistant-woocommerce/frontend/chat-widget.php`/`frontend/js/chat-widget.js`, new optional field on `admin/agent.py` `AgentTurnRequest`/`AgentContinueRequest`). `core/tracking/agent.py` `_build_system_prompt()` uses it as an explicit fallback/reinforcement for the response language - stated both right after the role definition (before the large German causal-chain data block) and again in the existing, unchanged relative language rule near the end of the prompt. Live-verified against the real Anthropic API: a thin-signal first message ("Hi") on an English-configured store now correctly answers in English (previously German), while a clearly English customer message on a German-configured store still correctly answers in English - the new fallback never overrides an actually detectable customer language. Entirely additive/optional: a request without `seiten_sprache` (older cached JS) behaves exactly as before.
* Fixed - the two status messages shown while the assistant is searching for products/checking prices ("Ich suche passende Produkte...", "Ich prüfe aktuelle Preise und Verfügbarkeit...") were hardcoded German `core/tracking/agent.py` constants, completely bypassing the plugin's own translation system - a shopper on an English-configured store would see these in German regardless. Now looked up per `seiten_sprache` (English + the plugin's four bundled German locale variants, which are textually identical to each other for these two sentences); an unrecognized store language falls back to English rather than German. A request without `seiten_sprache` keeps the previous unconditional German text. Also corrected the German wording to use proper umlauts ("prüfe"/"Verfügbarkeit" instead of the ASCII "pruefe"/"Verfuegbarkeit" - real customer-facing text, not a code comment, so the project's ASCII-comment convention didn't apply here).

2026-10-01 - version 1.0.8
* Changed - the real USD price list for the Marketplace Billing API channel is now configured (Dirk decision "Variante B", 01.10.2026, see NACHTRAG-usd-preisliste-billing-api-umstellung.md) - all eight subscription-tier environment variables and the four conversation-credit-package variables introduced (but deliberately left empty) in 1.0.7 now have real values in the deployment environment. The controlled 503 error path for a missing price stays in place as a regression guard for any future deployment where a variable is still unset.
* Changed - "Top up conversation credit" now offers all four package sizes for the Marketplace channel (250/1,000/5,000/20,000 conversations, `POST /tenants/{id}/guthaben-aufladen-link` now takes an `anzahl_gespraeche` field) - previously a single provisional package. Matches the existing dt-pm.eu package structure. An unknown package size is rejected with a clear 400 (no guessing), same principle as the "Upgrade plan" auto-next-tier logic. The dt-pm.eu/no-purchase-yet path is completely unaffected (ignores the new field, same static link as before).

2026-10-01 - version 1.0.7
* Changed - "Upgrade plan" and "Top up conversation credit" (Status tab) now call the WooCommerce Billing API (`POST /subscriptions/{contractID}`/`POST /charges`) for stores activated via a WooCommerce Marketplace contract number (`woocommerce_vertrags_id`), instead of linking to dt-pm.eu - avoids an external-upsell-link/foregone-revenue-share Marketplace policy risk for this group of stores. Stores activated via a dt-pm.eu license key (`dtpm_lizenzschluessel`) are completely unaffected, same links as before, no mixing of the two paths. The sandbox/production Billing API base URL (previously hardcoded to production) is now configurable (`WOOCOMMERCE_BILLING_API_ENV`, defaults to sandbox). The target plan for "Upgrade plan" is always the next tier up (no manual selection, same principle used everywhere else in this codebase) and the USD price is read from a dedicated environment variable per tier/billing period - deliberately not guessed from the existing EUR prices (the Billing API only supports USD), so the call fails with a clear error until a real, confirmed USD price list is configured. Cancellation (`DELETE`) was intentionally not implemented - whether it's needed at all is an open question (see Bestaetigungsbericht of this order).

2026-09-30 - version 1.0.6
* Added - `WC requires at least: 8.0`/`WC tested up to: 11.1` headers in ki-berater.php and readme.txt - WooCommerce Marketplace submission requirement (checked against the current WooCommerce major release, 11.1.x as of 01.10.2026). 8.0 as the floor because that is the oldest version conservatively covered by the plugin's actual code (no newer WooCommerce-only APIs are used beyond the HPOS Features API added below, which is itself guarded with `class_exists()`).
* Added - High-Performance Order Storage (HPOS/`custom_order_tables`) compatibility declaration via `FeaturesUtil::declare_compatibility()` on `before_woocommerce_init`, guarded with `class_exists()` for older WooCommerce installs - WooCommerce Marketplace submission requirement. No structural change needed: this plugin never reads/writes order data directly (confirmed by code audit, see RUECKMELDUNG-pruefung-woocommerce-marketplace-voraussetzungen.md Punkt 2), it only touches products (`wc_get_product()` et al.) and the standard `wc-ajax=add_to_cart` cart path, both unaffected by HPOS. Functionally verified with HPOS enabled in the local Docker test twin (dashboard/diagnosis pages render without errors).
* Changed - corrected the readme.txt description of where the chat widget appears - previous wording claimed "product pages or the homepage" only; in fact the widget is enqueued on every storefront frontend page (via `wp_enqueue_scripts`/`wp_footer`, unconditionally once a store is connected), including cart and checkout. This was already the actual behavior before this release - only the documentation was inaccurate, not the code. Also corrected the identical wording in the plugin's own in-admin Help page (`admin/help-page.php`, found while verifying the readme.txt fix) and updated all four bundled translations accordingly. No functional change.
* Added - `woocommerce/qit-cli` as a dev dependency (Quality Insights Toolkit, Marketplace submission requirement) plus a new `qit-test` CI job covering all 7 mandatory categories (Activation, Security, PHPCompatibility, Malware, Validation, API, End-to-End). The job skips itself with a clear reason until the one-time, necessarily human `vendor/bin/qit connect` login (real `dtdtpmde` partner account) has been done and its resulting `QIT_PARTNER_USER`/`QIT_PARTNER_TOKEN` are stored as repository secrets - that step cannot be performed by an AI assistant. The one QIT check that *can* run without that login (`qit woo:validate-zip`, local ZIP structure check) was run against this release's submission ZIP: passed ("ZIP file content is valid").

2026-09-30 - version 1.0.5
* Changed - reverted the plugin slug/text domain to "dtpm-ai-sale-assistant-woocommerce" (was "dtpm-ai-sale-assistant-for-woocommerce" in 1.0.4). While preparing the 1.0.4 package for submission, a local Plugin Check run flagged the bare "-woocommerce" suffix as a trademark violation, so it was changed to "-for-woocommerce" before submitting. The human WordPress.org reviewer then reserved the slug as "dtpm-ai-sale-assistant-woocommerce" (without "for-") during review (Review-ID dtpm-ai-sale-assistant-woocommerce/dtpm/28Sep26/T2 30Sep26/4.3) and noted that automated trademark hints can be false positives - the reviewer's own slug assignment is authoritative here, so the plugin now matches it. The display name stays "DT-PM AI Sale Assistant for WooCommerce". Renamed 497 occurrences of the string across the codebase (plugin folder, Text Domain header, .pot/.po/.mo filenames, docs, tests, build scripts); language file headers and code comments updated accordingly. No functional change. Lesson for future products (e.g. DT-PM Compliance for WooCommerce): keep taking the local Plugin Check trademark hint on "-woocommerce" suffixes seriously, but no longer treat it as binding without WordPress.org's own reviewer feedback.
* Added - `Requires Plugins: woocommerce` header (in both ki-berater.php and readme.txt), as recommended by the WordPress.org reviewer - since WordPress 6.5, Core automatically checks that WooCommerce is active before this plugin, instead of the plugin having to check that itself.

2026-09-29 - version 1.0.4
* Changed - corrected the plugin slug/text domain to "dtpm-ai-sale-assistant-for-woocommerce" (was "dtpm-ai-sale-assistant-woocommerce" in 1.0.3) to comply with the WooCommerce trademark policy for plugin slugs (allowed only as "for-"/"with-"/"using-"/"and-woocommerce", not as a bare suffix) - confirmed via a real WordPress.org Plugin Check run. No functional change.

2026-09-28 - version 1.0.3
* Changed - renamed the plugin from "DT AI Sale Assistant" to "DT-PM AI Sale Assistant for WooCommerce" (slug: dtpm-ai-sale-assistant-woocommerce, text domain updated to match) - purely a name/slug change, no functional change. Internal option/hook names are unaffected, so existing connections and settings carry over automatically.

2026-09-28 - version 1.0.2
* Changed - activating the plugin no longer automatically registers your store with our backend service (WordPress.org review, Guideline 7 - "automatically contact external servers without explicit and authorized consent") - it now waits for an explicit "Connect this store" click on the plugin's admin page. Sending shop URL/name to set up your account now only happens after that click, never on activation itself.
* Changed - the WordPress.org-submitted package no longer bundles the German translation files (`languages/*.po`/`*.mo`) - WordPress.org manages translations for listed plugins itself via translate.wordpress.org. The dt-pm.eu and WooCommerce Marketplace packages are unaffected and keep shipping the bundled translations.

2026-09-27 - version 1.0.1
* Fixed - the German store-language variants "Deutsch (Sie)" (de_DE_formal), "Deutsch (Österreich)" (de_AT), and "Deutsch (Schweiz)" (de_CH) now show the German admin interface and chat widget - previously only "Deutsch" (de_DE) was bundled, so WordPress silently fell back to English for the other three (WordPress does not automatically fall back from a locale variant to its base locale for plugin translations).
* Changed - added justified `phpcs:ignore` annotations for four Plugin Check warnings confirmed as false positives/non-issues on inspection (array-based input sanitization not recognized by the sniff; standard WooCommerce `tax_query` usage flagged as a generic possible-slow-query hint) - no behavior change.

2026-09-27 - version 1.0.0
* First official public release.

2026-09-27 - version 0.2.14
* Changed - the Status tab now clearly states when a paid plan's product limit has been reached (with a link to upgrade) - your plan's catalog limit is now actually enforced for new products, not just a pricing-page promise. Products already processed remain fully usable either way.

2026-09-27 - version 0.2.13
* Added - a new "Status" tab showing your current pricing tier, catalog usage against your plan's limit, and (on the free tier) remaining purchased conversation credit - with direct links to upgrade your plan or top up conversation credit.

2026-09-27 - version 0.2.12
* Added - on the Product Coverage tab, a specific notice when part of a catalog is queued because it exceeds the current plan's processing limit - it explains that those products will be processed automatically as capacity allows, instead of leaving the progress display looking stuck.

2026-09-27 - version 0.2.11
* Added - a "high demand" notice on the Product Coverage tab's processing progress if it hasn't advanced for a few minutes, so a long wait during busy periods no longer looks like a stuck or broken process.

2026-09-25 - version 0.2.10
* Fixed - several remaining German text fragments on the Product Coverage and Causal Chains tabs (the "still open" overview, the processing progress text, and the coverage-gap example SKUs list) now go through the same translation system as the rest of the admin UI.
* Fixed - the entire Diagnosis Wizard page, which had been missed by the previous English-conversion pass, is now fully translatable.

2026-09-25 - version 0.2.9
* Fixed - the Kern-API base URL now falls back to the production address (https://api.dt-pm.eu) instead of a local development address if the site's configuration is somehow missing - this only ever affected an edge case, not normal operation.
* Changed - removed a leftover development-only HTTP header from all API requests (had no effect on the production API).

2026-09-25 - version 0.2.8
* Added - a clear notice on the Settings tab when your dt-pm.eu license domain slot was released in your customer account and this shop is no longer connected to your license - previously this fell back to the free tier silently, with no explanation of what happened or how to reconnect.

2026-09-24 - version 0.2.7
* Changed - renamed the Product Coverage tab's "Reprocess all"/"Force: reprocess all from scratch" buttons to "Update changed products"/"Reprocess everything (ignore changes)" for clarity, since the former no longer means a full rebuild - added an explanatory tooltip to each.

2026-09-24 - version 0.2.6
* Changed - "Reprocess all" on the Product Coverage tab no longer deletes and rebuilds every product's AI-generated text - it now only reprocesses products that are new or have actually changed in WooCommerce since they were last processed, leaving unchanged products untouched.
* Added - a new "Force: reprocess all from scratch" button for the previous behavior (deletes and rebuilds everything, regardless of what changed) - useful after updating the causal chain itself.

2026-09-21 - version 0.2.5
* Added - the Causal Chains tab now shows the currently saved example questions (proactively suggested in the chat widget) as a simple list.
* Changed - the "Generate questions now" button is now always available for a confirmed causal chain, not just when none exist yet - clicking it replaces the current suggestions with newly generated ones.

2026-09-21 - version 0.2.4
* Fixed - the causal chain builder's friendly stage headings (e.g. "What determines the basic character?") only ever appeared for German-language stores - for any other store language they silently fell back to the raw internal stage name, because the matching relied on the (now translated) stage name itself instead of a language-independent marker.

2026-09-21 - version 0.2.3
* Fixed - proactive example questions shown when the chat widget first opens were always generated in German, regardless of the store's language - now uses the same site-language setting as the causal chain drafting and coverage checks.
* Added - optional extra spacing (px) between the chat widget and the bottom edge, for stores whose own cookie consent banner uses the same corner.
* Added - the product title in a recommended product card is now a link to the product's own page, opening in a new tab.

2026-09-20 - version 0.2.2
* Added - conversation credit (Gesprächsguthaben) - stores can now top up extra conversations beyond the free tier, with a "X of Y conversations remaining" display and a top-up link on the Settings tab for free-tier stores.

2026-09-20 - version 0.2.1
* Added - a "Start trial month" button on the Settings tab for free-tier stores, with the remaining trial days shown once started - the underlying one-time trial month feature already existed but had no way to actually start it from the store.

2026-09-19 - version 0.2.0
* Fixed - the chat widget's very first proactive greeting was a hardcoded German sentence, shown to every customer regardless of the store's language - it's now translated the same way as the rest of the widget.

2026-09-19 - version 0.1.99
* Fixed - same one-line sanitization form applied to the `relevant_attributes` request parameter in the same AJAX handler (Plugin Check submission warning).

2026-09-19 - version 0.1.98
* Fixed - sanitize the `category_ids` request parameter directly at the point of use in the product-coverage AJAX handlers (Plugin Check submission warning).
* Removed - the manual `load_plugin_textdomain()` call - unnecessary for a plugin listed on WordPress.org since WordPress 4.6, translations continue to work via the bundled `languages/` files.

2026-09-19 - version 0.1.97
* Fixed - every scheduled background check (license, trial-month, availability, coverage, and catalog-processing resume) now skips the network request entirely when the store isn't fully connected yet, instead of sending it and having it rejected by the server.

2026-09-19 - version 0.1.96
* Added - "Connect Purchase" now also accepts a dt-pm.eu license key (format `DTPM-XXXXX-XXXXX-XXXXX-XXXXX`) alongside the existing WooCommerce.com contract number - the format is detected automatically, no extra selection needed.

2026-09-18 - version 0.1.95
* Fixed - missing vertical spacing between stacked cards on several tabs (e.g. the "Open"/"outdated coverage" hints and the subcategory card on Product Coverage) - a used `mb-6` spacing utility was missing from the compiled admin CSS.

2026-09-18 - version 0.1.94
* Added - a full-width brand banner above the tab navigation on the dashboard, shown on all 5 tabs.

2026-09-17 - version 0.1.93
* Added - explanatory tooltips (hover/focus info icons) for harder-to-understand settings - AI model cost/control tradeoff, where to get a BYOK provider key, price tolerance below/above, variant classification, and the category-analysis "merge group"/"do not diagnose" controls.

2026-09-17 - version 0.1.92
* Added - the "Possible coverage gaps detected" hint on the Causal Chain page now updates immediately after saving, without a page reload - it reflects whether the automatic self-healing check (already run in the background on every save) actually resolved the gap.

2026-09-17 - version 0.1.91
* Added - the store's configured Site Language (Settings > General) is now passed to the AI for admin-triggered generation steps (causal chain draft, coverage check, tonality analysis, category analysis) - suggestions now come back in your store's language instead of always German. Falls back to German if the value can't be determined.
* Fixed - a false-positive Plugin Check warning about unsanitized input in the chat widget's product-lookup handler.

2026-09-13 - version 0.1.90
* Fixed - product catalog processing (Product Coverage step) no longer silently stops for good if a single product fails partway through a batch (e.g. a temporary AI service hiccup) - that one product is now skipped and logged, the rest of the batch/run continues.
* Added - an hourly automatic check that resumes catalog processing you already started if it looks like it stopped partway through unexpectedly (e.g. after a backend service restart) - see "External services" in readme.txt.

2026-09-11 - version 0.1.89
* Added - BYOK (bring-your-own-key) now supports Mistral as an alternative to Anthropic (Claude) - the settings page lets paid-tier stores choose which provider their own key is for, storing and encrypting whichever key matches the current selection. The free-tier BYOK restriction applies equally to both providers.

2026-09-09 - version 0.1.88
* Changed - BYOK (bring-your-own-key) is now a paid-tier feature - the free tier can no longer switch to a self-provided Anthropic API key; the settings page disables that option for free-tier stores with an explanatory note. Existing free-tier stores that had already set up BYOK keep it working (no forced reset).
* Changed - the chat widget now detects the WooCommerce category of the product page a conversation starts on and passes it to the advisor backend, so a conversation that begins on a specific product page gets more focused, faster answers.

2026-09-06 - version 0.1.87
* Added - translation infrastructure (languages/ folder with a .pot template and a complete German de_DE translation) - completing the conversion to English as the source language with German as the first full translation. The plugin now loads its bundled translation via load_plugin_textdomain().

2026-09-06 - version 0.1.86
* Changed - converted all visible admin-side JavaScript text (settings, category analysis, causal chains, product coverage) and the customer-facing chat widget to English source strings passed in from PHP, replacing hardcoded German - completing the TEIL A backend conversion with the same approach for JS.

2026-09-06 - version 0.1.85
* Changed - converted all visible wp-admin backend text (dashboard, settings, category analysis, causal chains, product coverage, help, diagnosis) to English source strings wrapped for translation, replacing hardcoded German. German remains fully supported as a translation (see languages/) once TEIL C of this conversion adds the .po/.mo files.

2026-09-06 - version 0.1.84
* Changed - the "Wissenspool" (shared knowledge pool) participation checkbox on the settings page now actually controls whether anonymized causal-chain patterns are contributed - previously cosmetic only. Mandatory (checked, locked) on the free tier; freely togglable on paid tiers. Removed the outdated mention of a discount that no longer applies.

2026-09-06 - version 0.1.83
* Added - one-time welcome notice after finishing initial setup (API credentials or connecting a purchase), with a quick 3-step guide and a link to the new Help tab.

2026-09-06 - version 0.1.82
* Added - new "Hilfe" tab on the dashboard with a short guide to every feature (Category Analysis, Causal Chains, Product Coverage, connecting a purchase, and the customer-facing chat widget).

2026-09-05 - version 0.1.81
* Fixed - the coverage-check example-product lookup now also matches by exact SKU, not just by product name/content - real products with a numeric or code-style SKU (e.g. "192433") were previously never found.

2026-09-05 - version 0.1.80
* Fixed - coverage-check example products now appear in a dedicated, always-visible section, so they're no longer silently missing when a subcategory already has a confirmed causal chain (the most common case in practice). Automatically carried over into the regular candidate list if you later click "Redraft".

2026-09-05 - version 0.1.79
* Replaced the remaining ae/oe/ue/ss transliteration with real German umlauts in visible admin and storefront text (headings, hints, button labels, status messages).
* Coverage-check hints on the Causal Chains tab now automatically add their example SKUs to the product candidate list (pre-checked, no duplicates) instead of only mentioning them in text.

2026-09-05 - version 0.1.78
* Added visible spacing between the subcategory dropdown and the card below it on the Causal Chains and Product Coverage tabs.

2026-09-05 - version 0.1.77
* Security - added tenant ownership checks to the remaining API endpoints that take a subcategory ID, so a valid tenant secret can no longer be used to read or modify another store's data via a guessed ID.

2026-09-04 - version 0.1.76
* Initial WordPress.org-ready release, used only by test/internal stores at this point - see 1.0.0 for the first official public release.
