# Changelog of SaaS Competitor Battlecards (`entranced_gelato/saas-competitor-battlecards`) Actor

- **URL**: https://apify.com/entranced\_gelato/saas-competitor-battlecards/changelog.md
- **Full Actor documentation**: https://apify.com/entranced\_gelato/saas-competitor-battlecards.md

## Changelog

All notable changes to this Actor are documented here. The format follows
[Keep a Changelog](https://keepachangelog.com/), and the project tries to
adhere to [Semantic Versioning](https://semver.org/) — `MAJOR.MINOR.PATCH`.

### \[0.2] — 2026-05 (launch-prep)

#### Added

- **In-output disclaimer.** Every battlecard now ships with a `disclaimer`
  field rendered at the top of `battlecard_markdown` and `one_pager_text`.
  Travels with every dataset record and every MCP tool call.
- **Per-competitor billing.** Pay-per-Result now bills $1 per chargeable
  competitor analysis. A `market_scan` with three resolved competitors
  produces three dataset records ($3); a `head_to_head` produces one ($1).
  Each record carries `primary_competitor` for auditing.
- **Chargeable / non-chargeable distinction.** Runs that end
  `candidates_only` or `failed` no longer push a dataset record (no charge).
  Users still see the result via the `OUTPUT` key-value record.
- **`chargeable_event_count` + `paid_event_name` fields** on every output —
  transparent billing receipt.
- **robots.txt enforcement** + per-host rate limiting (0.5 s) for every
  outbound HTTP request. Honors target-site preferences before fetching.
- **Top-level exception handler** in `main.py` — every run produces a
  structured record (success or failed). No silent crashes.
- **Competitor count cap (1–10)** at both the JSON Schema and Pydantic
  validation layers — bounds runtime + cost on adversarial inputs.
- **Locked dependency tree** (`requirements.lock.txt`) — production builds
  pin every transitive version, immune to upstream drift.
- **`.actorignore`** — keeps tests, dev requirements, scripts, and internal
  roadmap docs out of the published image.
- **Comprehensive smoke-test script** (`scripts/run_smoke.sh` +
  `scripts/smoke_test.py`) — validates the spec contract against the
  deployed Actor in both chargeable and non-chargeable branches.
- **Plain-language Terms of Use** (`TERMS.md`) inlined into the README so
  visitors can read them without leaving the listing page.
- **Test suite expanded to 120 unit tests** covering input validation,
  utils, discovery scoring, pricing extraction (incl. leaf-card detection
  and free/paid disambiguation), feature extraction (incl. blocklist,
  tagline, imperative-slogan filters), battlecard assembly, robots.txt,
  rate limiting, and per-competitor billing.

#### Changed

- **README** rewritten as a buyer-facing store listing — hero, who-it's-for,
  sample output, pricing, FAQ, then dev info at the bottom.
- **Pricing extractor** uses leaf-only card detection, eliminating the
  bullet-bleed bug between adjacent plan cards.
- **Free-detection** now scoped to the price-token window only — a casual
  "Free" mention inside another plan's bullets no longer flips that plan.
- **Feature extractor** prefers the dedicated features page over the
  homepage; falls back to homepage only when no features page resolves.
  Also drops footer/legal terms, marketing taglines (sentences with
  conjugated verbs), and imperative slogans.

#### Fixed

- `ensure_scheme()` is now case-insensitive on the scheme check
  (`HTTPS://x.com` no longer gets double-prefixed).
- `detect_billing_period()` recognizes spaced variants like `$10 / month`
  (real pricing pages use these).
- `chunk_unique()` filters whitespace-only strings.
- Confidence scoring no longer mixes float/int silently — Pydantic
  serialization warning eliminated.
- `head_to_head` strict semantics — flips to `candidates_only` if either
  side fails to resolve, instead of mislabeling as `partial`.
- `Actor.charge` call ordering — billing fields are now stamped before
  `push_data` so the dataset record reflects the billing decision.

#### Security

- Apify API token never echoed in script output (smoke test redacts it).
- robots.txt 401/403 conservatively treated as "disallow all".

### \[0.1] — Initial release

- First public version. Rule-based discovery, pricing extraction, feature
  extraction, and battlecard assembly. Markdown + one-pager outputs derived
  from canonical JSON.
