feat(license): add Lite SKU; remove user-facing free trial

Two coupled changes:

1. Lite tier
   - New Tier.LITE in src/license/schema.py.
   - FEATURES_BY_TIER[Tier.LITE] = {Deduplicator, Text Cleaner,
     Format Standardizer}. The three universally-useful tools that
     cover the most common bookkeeping / RevOps / Klaviyo prep
     workflows. Other six tools require Core.
   - i18n: license.tier_lite, license.feature_locked_title,
     license.feature_locked_body, license.upgrade_link,
     license.status_locked (en + es).
   - Per-tool feature gate at every GUI tool page
     (require_feature_or_render_upgrade) and every tool CLI
     (guard(feature=...)). A locked tool renders an upgrade
     prompt + Manage-license button (GUI) or exits with code 2
     (CLI).
   - Home grid: tool cards the user's tier doesn't unlock get a
     red 🔒 Locked badge in place of green Ready.

2. Trial removed
   - Activation form's "Start 1-year trial" button removed.
   - license_cli's `trial` subcommand removed.
   - activation.trial_button / activation.trial_help i18n keys
     dropped (pack parity test stays green).
   - Tier.TRIAL stays in the enum (back-compat with any field-
     tested trial licenses); LicenseManager._mint stays internal
     for tests and the seller's key generator.
   - Decision logged in DECISIONS §9b: a 1-year all-features
     trial undercuts paid Lite; paid-only keeps tier economics
     clean.

Tests (+29 net): +17 Lite-tier unit/guard tests + 13 Lite-tier
GUI tests + 1 trial-absent assertion - 2 trial CLI tests - 1
trial GUI button test. Total: 1995 → 2024.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 17:19:30 +00:00
parent e612c751a8
commit d32b58e61a
33 changed files with 621 additions and 153 deletions

View File

@@ -174,13 +174,14 @@ and proceeds.
- **Dev**: pytest, tox.
## 16. Test coverage
- 1,995 tests passing, 0 skipped, 0 xfailed.
- 1,843 core + CLI tests (run with `pytest -m 'not gui'` for a quick loop).
Includes 40 license-layer unit tests + 26 license-CLI tests.
- 152 GUI tests under `tests/gui/` driving Streamlit pages via `AppTest`
- 2,024 tests passing, 0 skipped, 0 xfailed.
- 1,859 core + CLI tests (run with `pytest -m 'not gui'` for a quick loop).
Includes 40 license-layer unit tests, 25 license-CLI tests, and
17 Lite-tier feature-map + guard tests.
- 165 GUI tests under `tests/gui/` driving Streamlit pages via `AppTest`
(smoke + EN/ES localization, chrome, gate, workflows, dedup review,
advanced panels, error paths, findings panel, activation + license
gate). Marked `gui`.
advanced panels, error paths, findings panel, activation +
license gate, Lite-tier per-page lock behaviour). Marked `gui`.
- Includes 15 perf-shape regression tests.
- Fixture corpora: text-cleaner (21), encodings (31), reference UTF-8 (9), format-cleaner (199 buyer cases + 20-row international stress fixture), missing-handler (3 use cases + 16 edge cases), column-mapper (3 use cases + 5 edge cases).
- Run: `python run_tests.py [--tool …] [--fixtures] [--coverage]`.
@@ -199,15 +200,31 @@ and proceeds.
(``DTLIC1:...``) on first launch; app verifies the signature
offline + matches the buyer-entered name/email to the embedded
values.
- **No free trial**: every license requires a paid blob from the
seller. The user-facing trial flow (button + ``license_cli trial``
subcommand) was removed in v1.6 to keep paid-tier economics clean.
- **Lifetime**: every license is 1 year by default. Renewal applies a
fresh blob without losing the embedded buyer identity.
- **Tiers**: ``trial``, ``core`` (the v1 SKU — all 9 tools), ``pro``,
``enterprise``. PRO and ENTERPRISE are scaffolded for future SKUs;
they currently unlock the same feature set as CORE.
fresh blob without losing the embedded buyer identity. Tier may
change during renewal (Lite → Core upgrade path).
- **Tiers**:
- ``lite`` — Deduplicator + Text Cleaner + Format Standardizer.
Buyer pays once, gets the three universally-useful tools.
- ``core`` — every Ready tool (all 9 in v1.6).
- ``pro``, ``enterprise`` — scaffolded for future SKUs; currently
mirror Core. Add per-SKU restrictions by editing
``FEATURES_BY_TIER`` in ``src/license/features.py``.
- ``trial`` — kept in the enum for backwards compat with any
field-tested trial licenses but no longer issuable.
- **Feature flags**: every tool has a stable feature id matching its
``tool_id`` in :mod:`src.gui.tools_registry`. Adding a future per-
tool SKU is a one-line change to ``FEATURES_BY_TIER`` — no consumer
code edits.
- **Per-tool gating**: each tool page (GUI) and tool CLI calls
``require_feature(FeatureFlag.<TOOL>)`` at entry. GUI shows an
upgrade prompt + button to the Activate page; CLI prints a
message naming the locked feature and exits with code 2.
- **Lock badge**: the home grid shows a red 🔒 Locked pill on tool
cards the current tier doesn't unlock.
- **Dev bypass**: ``DATATOOLS_DEV_MODE=1`` skips every check (used by
the test suite and during development).
- **No internet**: signature verification is fully offline. The