diff --git a/CHANGELOG.md b/CHANGELOG.md
index 52dbc2f..5e02001 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,11 +5,18 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/).
## [Unreleased]
+## [1.2.1] - 2026-10-03
+
+> This cumulative source release gathers changes since the published `v1.2.0` (2026-05-02). The duplicate September `[1.2.0]` heading below was a historical changelog label, not a separate published release.
+
### Fixed
- **RFC 3501 IMAP Date Format Locale Isolation (IMAP-003):**
- Resolved query syntax errors (`BAD Invalid date in SEARCH command`) during `older_than_days` IMAP rule searches on non-English (e.g. German `de_DE`) host locales.
- Implemented `format_imap_date` in `imap_client.py` using fixed RFC 3501 English month tokens (`Jan`..`Dec`) rather than runtime-locale-dependent `strftime("%d-%b-%Y")` (which produced localized abbreviations like `Mrz`, `Mai`, `Okt`, `Dez`).
- Added test coverage in `tests/test_imap_service.py` verifying RFC 3501 date-text formatting across all 12 calendar months and explicitly under active German locale.
+- **IMAP filter control-character rejection (2026-10-03):**
+ - Rejects CR, LF, and NUL in sender and subject inputs before trimming, so malformed rules do not reach IMAP `SEARCH` or deletion.
+ - Skips the entire invalid rule while continuing other safe rules; quoted-string backslash and quote escaping remains intact.
### Added
- **Pfad B Discoverability, Visual 4-View Architecture, Level 1 SBOM Stand 2026-10-03 & Contract Test Expansion (2026-10-03):**
@@ -69,7 +76,9 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/).
- Authored comprehensive bilingual Security Policy (`SECURITY.md`) establishing 48-hour response SLA and 5-day triage (`INV-SLA-10`), supported versions lifecycle (1.2.x), direct security coordinator contacts, private vulnerability advisory paths, and architectural local-first / zero-egress / non-elevated user-mode guarantees.
- Added 6 automated metadata contract tests in `tests/test_metadata.py` validating CI timeouts and concurrency, stale lifecycle automation, gitignore multi-host and lock defense, PEP 621 URL definitions and pytest options, bilingual security policy invariants, and changelog/marketing log recency.
-## [1.2.0] - 2026-09-12
+### Historical September work (originally labelled `[1.2.0]` on 2026-09-12)
+
+> Correction: this is a historical work entry, not a published `1.2.0` release. The published `v1.2.0` is dated 2026-05-02; this September work is included cumulatively in `1.2.1`.
### Added
- **Pfad B Discoverability, Visual Architecture & Governance Parity (2026-09-12):**
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 547661f..d9fd69d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -29,7 +29,7 @@ UniversalMailCleaner operates entirely in standard user mode (`RunAsInvoker`). C
### Strict Version Freeze Discipline
-Under policy `T-20260920-167562623`, the current version `1.2.0` is strictly frozen. Routine hygiene, CI matrix, and documentation changes must not bump version numbers; all updates are recorded under `## [Unreleased]` in `CHANGELOG.md`.
+Policy `T-20260920-167562623` keeps versions frozen by default. The user-authorized versioned source release recorded in master ticket `T-20261003-933110552` sets the current source-release version to `1.2.1`. Routine hygiene, CI matrix, and documentation changes must not bump it; interim changes are recorded under `## [Unreleased]` in `CHANGELOG.md`. Further version bumps require another explicitly authorized versioned release.
### Plan D Local Development Workflow
@@ -89,4 +89,4 @@ Die Anwendung läuft vollständig im unprivilegierten Standard-Benutzermodus ohn
### Version-Freeze-Disziplin (T-20260920-167562623)
-Die Version `1.2.0` bleibt eingefroren. Alle Änderungen werden unter `## [Unreleased]` im `CHANGELOG.md` erfasst.
+Die Freeze-Richtlinie `T-20260920-167562623` hält Versionen standardmäßig eingefroren. Die im Masterticket `T-20261003-933110552` dokumentierte Nutzerautorisierung setzt `1.2.1` als aktuelle Quellrelease-Version. Alltägliche Hygiene-, CI- und Dokumentationsänderungen erhöhen sie nicht; Zwischenänderungen stehen unter `## [Unreleased]` im `CHANGELOG.md`. Weitere Versionssprünge benötigen eine ausdrücklich autorisierte Versionsveröffentlichung.
diff --git a/MARKETING-LOG.txt b/MARKETING-LOG.txt
index 0786208..dad209e 100644
--- a/MARKETING-LOG.txt
+++ b/MARKETING-LOG.txt
@@ -1,6 +1,27 @@
# MARKETING-LOG — doc-bricks/UniversalMailCleaner
# Tracked Pfad B Discoverability, Visual Architecture, Governance & Verification Milestones
+================================================================================
+[2026-10-03 21:38 CEST] [VERSIONED_SOURCE_RELEASE_1_2_1_PREPARATION]
+Repository: doc-bricks/UniversalMailCleaner
+Branch: release/universalmailcleaner-1.2.1-20261003
+Version: 1.2.1 (user-authorized source-release candidate; master ticket T-20261003-933110552)
+License: MIT (SPDX-License-Identifier: MIT)
+Maintainer: Lukas Geiger (support@lukasgeiger.com)
+Security Contact: security@open-bricks.org, security@doc-bricks.org
+
+- Prepared the 1.2.1 version surfaces and cumulative changelog from the actual
+ published v1.2.0 release dated 2026-05-02; retained the September work entry
+ while correcting its duplicate historical 1.2.0 label.
+- Recorded IMAP sender/subject control-character rejection (CR, LF, NUL) and
+ per-rule fail-closed behavior while preserving safe rules and quoted-string
+ escaping.
+- Source release packaging will use the exact reviewed release commit with
+ `git archive --format=zip`; the archive will contain tracked repository files
+ only, excluding `.git` and untracked user profiles, with a SHA256SUMS.txt sidecar.
+- This entry records release preparation; it does not claim a tag, published
+ GitHub asset, Store package, or installed application.
+
================================================================================
[2026-09-12 16:00 CEST] [PFAD_B_DISCOVERABILITY_AND_DESIGN]
Repository: doc-bricks/UniversalMailCleaner
diff --git a/README-DE.md b/README-DE.md
index 5bb0101..91f0c96 100644
--- a/README-DE.md
+++ b/README-DE.md
@@ -8,7 +8,7 @@
[](LICENSE)
[](NOTICE)
-[](CHANGELOG.md)
+[](CHANGELOG.md)
[](#sec-10)
[](https://pypi.org/project/PySide6/)
[](pyproject.toml)
diff --git a/README.md b/README.md
index 3b245d6..1a90d85 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
[](LICENSE)
[](NOTICE)
-[](CHANGELOG.md)
+[](CHANGELOG.md)
[](#quick-start--setup)
[](https://pypi.org/project/PySide6/)
[](pyproject.toml)
diff --git a/README_de.md b/README_de.md
index 5bb0101..91f0c96 100644
--- a/README_de.md
+++ b/README_de.md
@@ -8,7 +8,7 @@
[](LICENSE)
[](NOTICE)
-[](CHANGELOG.md)
+[](CHANGELOG.md)
[](#sec-10)
[](https://pypi.org/project/PySide6/)
[](pyproject.toml)
diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md
index 67b07f9..eb98170 100644
--- a/THIRD_PARTY_LICENSES.md
+++ b/THIRD_PARTY_LICENSES.md
@@ -4,7 +4,7 @@
**Canonical Project License:** MIT License (`MIT`)
**Audit Date:** 2026-10-03 (Pfad B Discoverability & Architecture; Previous: 2026-10-01, 2026-09-26, 2026-09-22)
**Auditor:** Antigravity / Gemini (via GithubBot Pfad B)
-**Version:** `1.2.0`
+**Version:** `1.2.1`
**Umbrella Ecosystem:** `open-bricks` / `doc-bricks`
**Notice Attribution:** See canonical root [`NOTICE`](NOTICE) file.
diff --git a/THIRD_PARTY_LICENSES.txt b/THIRD_PARTY_LICENSES.txt
index 23086c7..7e93cf0 100644
--- a/THIRD_PARTY_LICENSES.txt
+++ b/THIRD_PARTY_LICENSES.txt
@@ -4,7 +4,7 @@ Project: UniversalMailCleaner (doc-bricks/UniversalMailCleaner)
Canonical License: MIT License (SPDX: MIT)
Audit Date: 2026-10-03 (Pfad B Discoverability & Architecture; Previous: 2026-10-01, 2026-09-26)
Auditor: Antigravity / Gemini (via GithubBot Pfad B)
-Version: 1.2.0 (Strictly frozen per T-20260920-167562623)
+Version: 1.2.1 (Strictly frozen per T-20260920-167562623)
Umbrella Ecosystem: open-bricks / doc-bricks
Attribution: See canonical root NOTICE file.
diff --git a/llms.txt b/llms.txt
index ef750db..c5eca58 100644
--- a/llms.txt
+++ b/llms.txt
@@ -9,7 +9,7 @@ UniversalMailCleaner is a local-first Windows desktop app for cleaning IMAP and
- Ecosystem Umbrella: open-bricks (https://github.com/open-bricks)
- License: MIT License (SPDX: `MIT`)
- Canonical Attribution: `NOTICE`
-- Version: 1.2.0
+- Version: 1.2.1
- Main app entry point: `mail_imap_cleaner_v1.py`
- Core modules: `imap_client.py`, `gmail_service.py`, `workers.py`, `models.py`, `scheduler_widget.py`, `profile_exchange.py`
- Third-Party License Inventory & Level 1 SBOM: `THIRD_PARTY_LICENSES.md` & `THIRD_PARTY_LICENSES.txt`
diff --git a/mail_imap_cleaner_v1.py b/mail_imap_cleaner_v1.py
index d9f6a53..0237234 100644
--- a/mail_imap_cleaner_v1.py
+++ b/mail_imap_cleaner_v1.py
@@ -74,7 +74,7 @@
# ==================== CONFIGURATION ====================
-__version__ = "1.2.0"
+__version__ = "1.2.1"
APP_NAME = "UniversalMailCleaner"
APP_VERSION = __version__
BASE_DIR = Path.home() / ".mail_cleaner"
diff --git a/pyproject.toml b/pyproject.toml
index d3fccc0..a5c2a6a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "universalmailcleaner"
-version = "1.2.0"
+version = "1.2.1"
description = "Local-first Windows desktop app for cleaning IMAP and Gmail mailboxes."
readme = "README.md"
requires-python = ">=3.9"
diff --git a/tests/test_metadata.py b/tests/test_metadata.py
index 384d631..be44c3e 100644
--- a/tests/test_metadata.py
+++ b/tests/test_metadata.py
@@ -92,7 +92,7 @@ def test_version_parity():
with open(pyproject_path, "rb") as f:
pyproject_data = tomllib.load(f)
version = pyproject_data["project"]["version"]
- assert version == "1.2.0", f"Unexpected version in pyproject.toml: {version}"
+ assert version == "1.2.1", f"Unexpected version in pyproject.toml: {version}"
# 2. mail_imap_cleaner_v1.py
main_py = ROOT / "mail_imap_cleaner_v1.py"
@@ -114,6 +114,16 @@ def test_version_parity():
content = readme_path.read_text(encoding="utf-8")
assert f"Version-v{version}-blue" in content or f"v{version}" in content
+ # 5. Machine-readable and third-party license version surfaces
+ version_markers = {
+ "llms.txt": f"- Version: {version}",
+ "THIRD_PARTY_LICENSES.md": f"**Version:** `{version}`
",
+ "THIRD_PARTY_LICENSES.txt": f"Version: {version}",
+ }
+ for filename, marker in version_markers.items():
+ content = (ROOT / filename).read_text(encoding="utf-8")
+ assert marker in content, f"Current version missing from {filename}"
+
def test_manifest_files_exist():
"""Verify all critical repo files exist and are non-empty."""
@@ -338,11 +348,11 @@ def test_statutory_notice_and_version_freeze():
assert "§ 521 BGB" in de_content
assert "Gefälligkeitsrecht" in de_content
- # Strict version freeze: version must be 1.2.0 across pyproject and main
+ # Strict version freeze after authorized versioned source release: 1.2.1
pyproject_path = ROOT / "pyproject.toml"
with open(pyproject_path, "rb") as f:
data = tomllib.load(f)
- assert data["project"]["version"] == "1.2.0"
+ assert data["project"]["version"] == "1.2.1"
def test_utf8_hygiene():
@@ -542,7 +552,8 @@ def test_contributing_guide_present_and_invariants():
assert "RunAsInvoker" in content
assert "INV-USER-02" in content
assert "T-20260920-167562623" in content
- assert "1.2.0" in content
+ assert "T-20261003-933110552" in content
+ assert "1.2.1" in content
assert "Plan D" in content
for inv in INVARIANTS:
assert inv in content, f"Invariant {inv} missing in CONTRIBUTING.md"