Skip to content

story: stories, albums, viewers and stealth on the registry - #12

Merged
erfnzdeh merged 10 commits into
mainfrom
feat/pr8-story
Sep 4, 2026
Merged

story: stories, albums, viewers and stealth on the registry#12
erfnzdeh merged 10 commits into
mainfrom
feat/pr8-story

Conversation

@erfnzdeh

@erfnzdeh erfnzdeh commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

PR-8 of the v2 plan: stories on the operation registry — 31 operations under story (feed all/hidden/peer, get by id or link, read, react, reply, share, post/edit/delete with the full privacy-rule vocabulary and media areas, pin/unpin/reorder on profile, archive, albums, viewers list with reactions/search/export, hide/unhide peers, the story-only blocklist, stealth mode, stats, search, live stories, story watch). user hide-stories stays invocable as a legacy path of story hide.

  • Privacy rules reuse the account group's vocabulary; media areas take payload@X,Y,W,H[,ROT[,RADIUS]] sugar over an authoritative --areas JSON that story get --areas-out round-trips.
  • story read clears your own unread ring and tells the poster nothing; appearing in their viewer list costs an explicit --register-view.
  • Honest limit: story live get cannot reach the stream's viewer count/publisher in layer 227 and says so.

What the rebase onto main changed

Three of the branch's decisions were written against a main that has since moved, and were merged rather than replayed:

  • One "Hide Stories" toggle. PR-5 landed user.hide-stories as an operation of its own while this branch made user hide-stories a legacy path of story.hide — and the registry refuses one alias claimed by two ops. story hide keeps the implementation and absorbs what the user op had that it did not (several peers in one pass, --all for the whole bar); user hide-stories is now purely the §12.4 path onto it. AGENT.md's four frozen keys (user_id, username, hidden, already), the idempotence and the bulk peers shape are unchanged, and PR-5's contract tests now exercise them through story.hide.
  • One event taxonomy. PR-4 already names all six story constructors in core/eventtypes.py and already subscribes with a single events.Raw() handler, so the branch's second normaliser and second Raw handler are gone: the story payload shaping is a branch inside normalise_update, keeping the fine-grained kind that tells a received story reaction from one this account sent.
  • Nine story waivers dropped rather than merged. PR-5, PR-7 and PR-11 landed ahead of this one and cover close friends, boost status and the whole live-story call surface outright, so stories needs only 7 waivers, not 16.

The fake Telegram client is one merged file now, so nine handler pairs were merged by hand rather than shadowed: SearchPosts dispatches on the TL namespace (messages. vs stories. share a class name), LoadAsyncGraph on the token, and the blocklist, hidden-peers and read-marker stores collapsed onto one field each.

Numbers

8 commits, 10,449 tests green, ruff + mypy clean, make docs parity reproduces the checked-in artefacts. Parity: stories 113/120 required ids covered and 100 % accounted; P0 floor 148 → 161, covered floor 1285 → 1390; total 1390/1797 covered, 100 % accounted.

Three shapes exist because the API makes a distinction the GUI hides: a
story item comes back as one of three TL classes for one id, an audience
is a base rule plus exceptions rather than a value, and the viewers
screen mixes plain views with forwards and reposts. Media areas are
flattened into one struct with a type discriminator so that
`story get --areas-out` writes JSON `story post --areas` reads back.
Four RPCs behind one `story list` because the GUI shows one grid with
tabs; `story read` clears the unread ring and only `--register-view`
puts the account in the poster's viewer list, because an agent that
silently appears there is a privacy bug. The feed pages on an opaque
state rather than an offset, so its cursor carries the state and the
next flag instead of an id that would restart the walk.
The v1 command, its IPC route and ClientWrapper.set_stories_hidden() are
gone; the path stays invocable because the op declares it as a legacy
path, --unhide included. That makes the registry generate the 'user'
group, so 'user get' and 'user dialog-status' move into LEGACY_EXTRAS
until PR-5 migrates them rather than being a second group of the same
name, which build_cli() refuses on purpose.
The whole-domain waiver is gone: 104 of the 120 required ids are
covered and the remaining 16 name the group that owns them — close
friends are contacts, the live-story call is 'vc', story notifications
are 'notify'. Three ids other domains had waived to PR-8 or PR-5 are
covered here instead, so their waivers go too.
…o watch

Telethon has no event builder for stories, so the six story updates only
arrive through a Raw handler. They get their own normaliser rather than a
branch in normalise(): the raw feed also carries UpdateNewMessage, whose
class name matches that function's substring table and would emit a
second, empty message_new beside the real one.
The fake grows real story items per peer, a profile page and an archive
that pin/unpin really move ids between, albums, viewer rows and the
opaque feed state. The suite asserts the three things only a request can
show: reading a story sends readStories and nothing else, the privacy
vector is base-then-allow-then-disallow, and a channel story's viewers
come from getStoryReactionsList with the source named in a warning.

canSendStory has no result union on layer 227 — the server raises — so
the refusal is read off the error, keeping the seconds or boosts the
message carries.
…ind it

AGENT.md gains a Stories section built around the four rules that bite:
reading is not being seen, the audience is a base rule plus exceptions in
that order, a feed placeholder is not a caption-less story, and the post
quota moves under you. The v1 'user hide-stories' paragraph now points at
'story hide' and keeps its promise. CHANGELOG records the group, the one
deletion and the paths that survive it.
…lags

getPeerStories hands back the peer's whole active set in one call, so
guessing has_more from a full page there would hand out a cursor that
returns nothing. The condition now has a name and the comment says why.
Three of this branch's decisions were written against a `main` that has
since moved. Replaying them verbatim would have produced a tree that does
not import, so they are merged rather than repeated.

`user hide-stories`. PR-5 landed it as an operation of its own while this
branch declared the same path as a legacy path of `story hide`, and the
registry refuses one alias claimed by two ops — correctly, because a
toggle with two implementations is a toggle that will disagree with
itself. `story hide` keeps the implementation and absorbs what the `user`
op had that it did not: several peers in one pass, and the whole-bar
toggle. AGENT.md's four frozen keys, the idempotence and the bulk `peers`
shape are unchanged, and PR-5's contract tests exercise them through
`story.hide`. `hidden` and `already` lose their defaults so that
`omit_defaults` cannot drop the two false values AGENT.md publishes.

Story events. PR-4's taxonomy already names all six story constructors and
the daemon already subscribes with one `events.Raw()` handler, so the
second normaliser and the second handler are gone: the payload shaping is
a branch inside `normalise_update`, keeping the fine-grained `kind` that
tells a received story reaction from one this account sent.

Waivers. PR-5, PR-7 and PR-11 cover close friends, boost status and the
whole live-story call surface outright, so `stories` needs 7 waivers
rather than 16 and the floors rise to what the registry now claims.

The fake client is one merged file, so nine handler pairs are merged by
hand rather than shadowed: `SearchPosts` dispatches on the TL namespace
(`messages.` and `stories.` share a class name), `LoadAsyncGraph` on the
token, and the blocklist, hidden-peer and read-marker stores collapse onto
one field each.
@erfnzdeh
erfnzdeh merged commit 15754e4 into main Sep 4, 2026
20 checks passed
@erfnzdeh
erfnzdeh deleted the feat/pr8-story branch September 4, 2026 01:24
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