Skip to content

Add chappe compare for cross-channel post leaderboards#1

Merged
crimeacs merged 1 commit into
mainfrom
feature/compare-command
May 19, 2026
Merged

Add chappe compare for cross-channel post leaderboards#1
crimeacs merged 1 commit into
mainfrom
feature/compare-command

Conversation

@crimeacs
Copy link
Copy Markdown
Owner

Summary

  • New top-level command: chappe compare @ch1 @ch2 [@ch3 ...] --by forwards|views|replies|reactions|engagement --limit 5 --period 365d
  • Returns per-channel top posts + a combined leaderboard sorted across all channels + a summary that names the mean-forward-rate leader and the raw-metric leader.
  • Composes existing helpers (rank_posts, filter_posts_by_period, _ranking_metric_quality); no schema or store changes.

Why

Channel owners and agents already use chappe posts top per channel; doing peer-benchmarking today requires running posts top N times and stitching the JSON yourself. compare makes that one call. Concretely: pointed at four RU AI/tech channels (~420 posts), the command surfaced the forward-rate leader in the niche in <1s and produced the combined top-12 list of viral posts across all of them.

Output shape

{
  "ok": true,
  "channels": ["@a","@b","@c"],
  "by": "forwards",
  "per_channel": { "@a": { "posts_available": 100, "metric_quality": {...}, "top_posts": [...] }, ... },
  "combined_leaderboard": [ { "channel": "@a", "id": "...", "views": ..., "forwards": ..., ... }, ... ],
  "summary": {
    "channels_compared": 3,
    "posts_compared": 300,
    "by_forward_ratio_winner": { "channel": "@a", "mean_forward_rate": 0.014 },
    "by_raw_metric_winner": { "channel": "@b", "metric": "forwards", "value": 4436, "post_id": "...", "link": "..." },
    "mean_forward_rate_by_channel": { "@a": 0.014, "@b": 0.011, "@c": 0.008 }
  },
  "unsynced_channels": [],
  "next_commands": [ "chappe briefing @a", ... ]
}

Test plan

  • pytest -q — 41 passed (38 baseline + 3 new)
  • ruff check src/ tests/ — clean
  • Smoke-tested live against four RU channels (@nn_for_science @denissexy @seeallochnaya @ai_newz); summary + combined leaderboard come back correctly and the forward-rate winner is computed using the same forward_rate = forwards/views definition as enrich_post
  • compare with one channel returns USAGE_ERROR ("compare requires at least two channels")
  • compare against an unsynced handle returns the channel in unsynced_channels and emits a chappe sync ... next_command

🤖 Generated with Claude Code

`chappe compare @ch1 @ch2 [@ch3 ...] --by forwards|views|replies|reactions|engagement`
returns, per channel, the top posts by the chosen metric, plus a single combined
leaderboard sorted across all channels and a summary that names the
mean-forward-rate leader and the raw-metric leader.

Useful for channel owners comparing their post performance against peers: which
post format ships forwards-per-view best across a niche, and which post is the
single biggest hit. Composes the same store + rank_posts + _ranking_metric_quality
helpers as `posts top`, with `filter_posts_by_period` applied per channel.

- analytics.compare_channels: pure function over dict[channel→posts]
- cli.compare: top-level command, requires ≥2 channels, validates --by, surfaces
  per-channel metric_quality and emits sync next_commands for any unsynced channel
- 3 new tests covering arg validation, per-channel + combined leaderboards, and
  the unsynced-channel next-command path
crimeacs added a commit that referenced this pull request May 19, 2026
The first cut was a generic dark stats card. This rewrites the renderer as a
vintage-dispatch poster that pairs the Chappie mascot with the channel's
strongest post as a pull-quote, sits on cream paper with deterministic noise,
and prints in a strict 3-ink palette (forest green, sepia, cream).

Visual moves
- Mascot is the hero. _load_mascot_keyed() alpha-keys the near-white sky in
  the source illustration so Chappie sits directly on the paper instead of
  inside a hard rectangle.
- Mascot rotates per channel via deterministic seed (channel handle hash),
  picking from chappie-recorder, signal-operator, lookout, night-watch, or
  scout-map-reader. Same channel always renders the same mascot.
- Channel name in Baskerville Bold (true upright weight via display_bold
  font role), not Hoefler Black Italic which is what serif_black resolves to
  on macOS.
- Pull-quote from the #1 post by forwards in serif Regular, with a faint
  oversized opening quote ornament so the quote teases without competing
  with the masthead.
- Two feature stats below the quote: top-post forwards and the channel's
  mean forward rate.
- Bottom ledger is four numeric cells with a consistent rhythm (posts,
  comments, questions, peak views) plus thin vertical separators.
- Footer attribution + monospaced URL.

Stats fixes
- _best_question() now ranks comment questions by reactions then length,
  filtering out trivially short ones. Lands on substantive questions
  instead of the first ?-ending fragment in the corpus.
- compute_dashboard_stats() distinguishes most_used_format (count) from
  best_format_by_lift (forward rate). The visual no longer surfaces the
  bare 'photo' label; the caption shows both axes.
- New peak_views and peak_forwards rollups.

Assets shipped in src/chappe/assets/ so they ride along in the wheel:
chappie-recorder.png, chappie-signal-operator.png, chappie-lookout.png,
chappie-night-watch.png, chappie-scout-map-reader.png.
@crimeacs crimeacs merged commit 64d0a20 into main May 19, 2026
4 checks passed
@crimeacs crimeacs deleted the feature/compare-command branch May 19, 2026 18:30
crimeacs added a commit that referenced this pull request May 19, 2026
…ion (#2)

* Add chappe wrapped: shareable PNG dashboard + caption per channel

`chappe wrapped @channel --period 90d [--lang en|ru] [--out PATH]` reads the
local store, computes channel stats (posts, comments, mean forward-rate, best
format, top 3 by forwards, sample audience question), and writes a 1080x1350
PNG card plus a ready caption .txt. The PNG carries 'generated by chappe ·
github.com/crimeacs/chappe' in the footer, so each post published from it is a
quiet referral.

Wired into onboarding:

- bootstrap fastest_path_to_value now suggests `chappe wrapped` once a channel
  has ≥20 local posts. The 'why' explicitly frames it as a free engagement post.
- onboard setup_steps appends a publish_wrapped_dashboard step at the end of
  analyze_growth.

This makes the first reachable payoff after a fresh sync a tangible image the
operator can post immediately, not just JSON. The Chappe attribution turns each
adopter's first post into a growth loop.

- new dashboard.py: pure rendering (Pillow) + compute_dashboard_stats + bilingual
  render_caption; tolerates missing Cyrillic glyphs by falling back through a
  font-path candidate list (Arial → DejaVu)
- new pyproject dep: Pillow>=10
- new cli command `wrapped` and two new onboarding steps
- 3 new tests: png magic bytes + caption file + sync next_command on unsynced +
  bootstrap surface for the new fastest-path step

* Redesign chappe wrapped: magazine-cover poster with brand assets

The first cut was a generic dark stats card. This rewrites the renderer as a
vintage-dispatch poster that pairs the Chappie mascot with the channel's
strongest post as a pull-quote, sits on cream paper with deterministic noise,
and prints in a strict 3-ink palette (forest green, sepia, cream).

Visual moves
- Mascot is the hero. _load_mascot_keyed() alpha-keys the near-white sky in
  the source illustration so Chappie sits directly on the paper instead of
  inside a hard rectangle.
- Mascot rotates per channel via deterministic seed (channel handle hash),
  picking from chappie-recorder, signal-operator, lookout, night-watch, or
  scout-map-reader. Same channel always renders the same mascot.
- Channel name in Baskerville Bold (true upright weight via display_bold
  font role), not Hoefler Black Italic which is what serif_black resolves to
  on macOS.
- Pull-quote from the #1 post by forwards in serif Regular, with a faint
  oversized opening quote ornament so the quote teases without competing
  with the masthead.
- Two feature stats below the quote: top-post forwards and the channel's
  mean forward rate.
- Bottom ledger is four numeric cells with a consistent rhythm (posts,
  comments, questions, peak views) plus thin vertical separators.
- Footer attribution + monospaced URL.

Stats fixes
- _best_question() now ranks comment questions by reactions then length,
  filtering out trivially short ones. Lands on substantive questions
  instead of the first ?-ending fragment in the corpus.
- compute_dashboard_stats() distinguishes most_used_format (count) from
  best_format_by_lift (forward rate). The visual no longer surfaces the
  bare 'photo' label; the caption shows both axes.
- New peak_views and peak_forwards rollups.

Assets shipped in src/chappe/assets/ so they ride along in the wheel:
chappie-recorder.png, chappie-signal-operator.png, chappie-lookout.png,
chappie-night-watch.png, chappie-scout-map-reader.png.
crimeacs added a commit that referenced this pull request May 19, 2026
User-facing additions since 0.1.2:

- chappe compare @ch1 @ch2 [...]: cross-channel leaderboard with mean
  forward-rate leader and raw-metric winner. PR #1.
- chappe wrapped @channel: PNG channel-dashboard renderer plus caption
  template with Chappe footer attribution; mascot rotates per channel and
  Pillow renders cream-paper letterpress style. Onboarding now surfaces it
  as the first reachable payoff once a channel has ≥20 stored posts. PR #2.
- New Pillow>=10 dependency.
- Bundled five Chappie mascot illustrations inside the wheel.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant