Skip to content

feat: typed ForYouFeed model + make get_for_you_feed typed-mode aware#99

Merged
ColonistOne merged 1 commit into
mainfrom
feat/for-you-feed-typed-model
Jul 15, 2026
Merged

feat: typed ForYouFeed model + make get_for_you_feed typed-mode aware#99
ColonistOne merged 1 commit into
mainfrom
feat/for-you-feed-typed-model

Conversation

@ColonistOne

Copy link
Copy Markdown
Collaborator

A consumer (me, driving the plugin) mis-parsed get_for_you_feed() on the first pass because its response is an envelope, not a bare post list, and nothing in the type surface made that obvious. This makes the shape a first-class, machine-checked model.

The problem

get_for_you_feed() returns:

{"items": [{"kind": "post"|"comment", "post": {...}|None, "comment": {...}|None,
            "reason": str|None, "match_score": float,
            "on_post_id": str|None, "on_post_title": str|None}],
 "personalised": bool, "count": int}

Two easy-to-miss things: (1) every other list endpoint returns bare objects, but this one wraps each item in a ranking envelope; (2) the actual post/comment is nested under item["post"] / item["comment"] and discriminated by kind, not at the item top level. Reading item["id"] / item["title"] silently yields None. It was also the only reader method that ignored typed=True — it always returned a raw dict.

The change

  • Add ForYouEntry / ForYouFeed frozen dataclasses (from_dict/to_dict, reusing the existing Post/Comment models), exported from the package alongside the other response models.
  • Wire both the sync and async get_for_you_feed through _wrap(..., ForYouFeed) so typed=True returns a model — consistent with every other reader method.
  • Expand the docstrings to spell out the envelope and the kind discriminator.
  • Tests for the models and for typed-mode wrapping; CHANGELOG entry under Unreleased.

Compatibility

No behavior change with typed=False (the default) — the raw dict is returned exactly as before, proven by a test. typed=True now returns ForYouFeed instead of an unwrapped dict (previously an inconsistency).

Checks

ruff check + ruff format --check + mypy src/ clean; full suite green (1005 passed), new code fully covered.

🤖 Generated with Claude Code

…de aware

get_for_you_feed() returns an envelope, not a bare post list:
{items: [{kind, post|comment, reason, match_score, on_post_id, ...}],
personalised, count}. It was the only reader method that ignored typed=True
(always returned a raw dict), and its nested, kind-discriminated shape is easy
to mis-read (post/comment live under item["post"]/item["comment"], not at the
item top level) — which is exactly the shape no docstring/type made obvious.

- Add ForYouEntry / ForYouFeed frozen dataclasses (from_dict/to_dict, reusing
  Post/Comment), exported from the package like the other response models.
- Wire the sync + async get_for_you_feed through _wrap(..., ForYouFeed) so
  typed=True returns a model, consistent with every other reader method.
- Expand the docstrings to spell out the envelope + the kind discriminator.
- Tests for the models and typed-mode wrapping; CHANGELOG entry.

No behavior change with typed=False (the default). ruff + mypy clean, tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TRn9SBFGaxRwZbwRsKNJ7b
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@ColonistOne ColonistOne merged commit a902cb3 into main Jul 15, 2026
7 checks passed
@ColonistOne ColonistOne deleted the feat/for-you-feed-typed-model branch July 15, 2026 03:55
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