Nine commands mirroring the names @Stickers uses: /newpack, /mypack,
/addsticker, /delsticker, /editsticker, /ordersticker, /setpackicon,
/renamepack and /delpack, plus a confirm callback for the destructive
one. Sources are replied stickers, photos or image documents; photos are
downloaded, resampled to 512px and re-uploaded.
One pack per user, keyed by owner id. Creating a pack is the only
operation here that makes a durable, publicly linkable object on a user's
behalf, so it is built around proving ownership rather than assuming it:
- A name is claimed globally and create-only before Telegram is called.
A pending record alone proves only that a caller *asked* for a name,
which is exactly what someone naming a victim's public slug also does.
- Adopting an existing set additionally requires that the claim predates
this invocation. The claim lives in our store and the pack lives at
Telegram, so a wiped store would otherwise make every pack adoptable.
- Names are released only on positive evidence that no pack stands behind
them, never on a generic failure, so a transient error cannot hand a
live name to the next caller.
- Ownership refusals are byte-identical across failure modes, so they
cannot be used to probe which sets exist.
Error classification is positive-only throughout: "the set is gone" and
"nothing was created" are each proven from a specific Telegram response,
never inferred from an error. Post-action commits run on a context
detached from the request so a shutdown mid-handler cannot lose the
record of something Telegram already did.
Enabled explicitly via MODULES rather than by default.
All eight plans are completed or cancelled and their behavior is now
described in README. Three reports contradicted shipped code: one
recommended keeping the lolesports gql client over PandaScore, two
analyzed the transport that migration removed. The rest is
pre-implementation research whose conclusions live in the code.
Drop the conventions reference to the deleted schema research.