<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Matrix.org - Tech</title>
    <subtitle>The Matrix.org Foundation</subtitle>
    <link href="https://c956b204.matrix-website.pages.dev/category/tech/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://c956b204.matrix-website.pages.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-01-06T18:00:00+00:00</updated>
    <id>https://c956b204.matrix-website.pages.dev/category/tech/atom.xml</id>
    
    
    
    
<entry xml:lang="en">
    <title>Authentication changes on Matrix.org</title>
    <published>2025-01-06T18:00:00+00:00</published>
    <updated>2025-01-06T18:00:00+00:00</updated>
    <author>
      <name>Will Lewis</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2025/01/06/authentication-changes/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2025/01/06/authentication-changes/</id>
    <content type="html">&lt;p&gt;The Matrix.org homeserver will see changes related to authentication in Q1 2025. The team will turn off guest account access on Matrix.org on January 16th and roll out Matrix Authentication Service (MAS) to embrace Matrix 2.0 after February 10. Client developers need to ensure their clients support the required changes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-mas&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-is-mas&quot; aria-label=&quot;Anchor link for: what-is-mas&quot;&gt;🔗&lt;&#x2F;a&gt;What is MAS&lt;&#x2F;h2&gt;
&lt;p&gt;Matrix Authentication Service is Matrix&#x27;s next-generation authentication stack. It allows for more flexible authentication journeys without requiring client developers to support every one of them.&lt;&#x2F;p&gt;
&lt;p&gt;You can find all the technical details in Quentin&#x27;s Matrix Conf talk, &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=wOW8keNafdE&quot;&gt;Harder Better Faster Stronger Authentication with OpenID Connect&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;what-s-the-impact&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-s-the-impact&quot; aria-label=&quot;Anchor link for: what-s-the-impact&quot;&gt;🔗&lt;&#x2F;a&gt;What&#x27;s the impact&lt;&#x2F;h2&gt;
&lt;p&gt;Client developers need to ensure that their projects support &lt;a href=&quot;https:&#x2F;&#x2F;areweoidcyet.com&#x2F;#next-gen-auth-aware-clients&quot;&gt;the requirements listed on areweoidcyet.com&lt;&#x2F;a&gt; and, more precisely, the requirements listed in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-spec-proposals&#x2F;pull&#x2F;3824&quot;&gt;MSC3824&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Developers can already use beta.matrix.org to see if their clients are compatible with MAS. &lt;strong&gt;If you notice anything that doesn&#x27;t work as intended, make sure to give your feedback on &lt;a href=&quot;https:&#x2F;&#x2F;areweoidcyet.com&#x2F;#next-gen-auth-aware-clients&quot;&gt;those MSCs&lt;&#x2F;a&gt;.&lt;&#x2F;strong&gt; If clients work on beta.matrix.org, they will be able to connect to matrix.org after the rollout.&lt;&#x2F;p&gt;
&lt;p&gt;Homeserver administrators from the public federation don&#x27;t have to worry about this deployment. MAS only affects the APIs between the clients and the server, so this deployment only impacts clients connecting to matrix.org. Federation APIs, used for servers to talk to each other, remain unchanged.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;disabling-guest-accounts&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#disabling-guest-accounts&quot; aria-label=&quot;Anchor link for: disabling-guest-accounts&quot;&gt;🔗&lt;&#x2F;a&gt;Disabling guest accounts&lt;&#x2F;h2&gt;
&lt;p&gt;Guest accounts are a legacy Matrix feature that allows clients to create temporary, limited technical accounts to participate in specific rooms that allow it.&lt;&#x2F;p&gt;
&lt;p&gt;The Matrix.org Foundation would have liked to find an efficient way to let people create guest accounts when joining a conversation and then turn them into fully fledged accounts later. Nobody in the ecosystem found resources to design and implement such a user journey, and guest accounts ended up being used for technical reasons, like displaying room previews or badges via shields.io.&lt;&#x2F;p&gt;
&lt;p&gt;Those accounts make up a significant load on the matrix.org homeserver. For that reason, the Matrix.org Foundation has decided to disable them at least temporarily to save precious resources and go ahead with the rollout of the new authentication stack.&lt;&#x2F;p&gt;
&lt;p&gt;The Matrix.org Foundation is open to re-enabling guests accounts once it has the financial capacity to support them. If guest accounts on matrix.org are important to you and your business, please &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;membership&#x2F;&quot;&gt;join the Matrix.org Foundation as a supporting member&lt;&#x2F;a&gt; to contribute to its financial sustainability.&lt;&#x2F;p&gt;
&lt;p&gt;We encourage developers using guest access for room information, such as topics, aliases, or member counts, to utilize the endpoint proposed by &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-spec-proposals&#x2F;pull&#x2F;3266&quot;&gt;MSC3266&lt;&#x2F;a&gt;. This endpoint is publicly accessible without authentication and can serve as an alternative resource until guest access is reinstated in a more robust form.&lt;&#x2F;p&gt;
&lt;p&gt;We appreciate your understanding as we take these steps to enhance the user experience on Matrix.org.&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>Sunsetting the Sliding Sync Proxy: Moving to Native Support</title>
    <published>2024-11-14T16:00:00+00:00</published>
    <updated>2024-11-14T16:00:00+00:00</updated>
    <author>
      <name>Will Lewis</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2024/11/14/moving-to-native-sliding-sync/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2024/11/14/moving-to-native-sliding-sync/</id>
    <content type="html">&lt;p&gt;&lt;em&gt;We will be decommissioning the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-spec-proposals&#x2F;pull&#x2F;3575&quot;&gt;sliding sync proxy&lt;&#x2F;a&gt; next week (21&#x2F;11&#x2F;2024) and Element are removing client support in mid-January (17&#x2F;01&#x2F;2025).&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Sliding Sync is designed to provide a significantly faster and more scalable sync experience in our clients. The initial implementation was first prototyped in Element Web backed by an entirely experimental server proxy. The implementation had half an eye on low bandwidth use cases, and the prototype led to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-spec-proposals&#x2F;pull&#x2F;3575&quot;&gt;MSC3575&lt;&#x2F;a&gt;. We then realised that a simpler approach would be beneficial, and reused the same (experimental) proxy concept to facilitate beta testing with Element X, this time making it available on matrix.org. In doing so, we learned valuable lessons, leading to a refined and simplified API design in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-spec-proposals&#x2F;pull&#x2F;4186&quot;&gt;MSC4186&lt;&#x2F;a&gt;. The proxy itself was only ever considered as a temporary arrangement to aid speed of development, rather than being a long term solution.&lt;&#x2F;p&gt;
&lt;p&gt;Simplified Sliding Sync &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-spec-proposals&#x2F;blob&#x2F;erikj&#x2F;sss&#x2F;proposals&#x2F;4186-simplified-sliding-sync.md&quot;&gt;MSC4186&lt;&#x2F;a&gt; (also known as native sliding sync), has since been implemented in Synapse, with encouraging results. Now that we don’t expect the API shape to change significantly, we recommend homeserver developers to implement MSC4186 natively.&lt;&#x2F;p&gt;
&lt;p&gt;The Matrix.org Foundation does not have the resources to keep up maintenance of the proxy service or its codebase, and plans to decommission the proxy from Mid-November and archive the sliding-sync repo.&lt;&#x2F;p&gt;
&lt;p&gt;Recognising that the community needs time to adopt sliding sync natively, Element will keep client support for the old API (MSC3575) until the 17th of January, 2025.&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;the-timeline&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-timeline&quot; aria-label=&quot;Anchor link for: the-timeline&quot;&gt;🔗&lt;&#x2F;a&gt;The Timeline&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Now: EX Apps support migrating from the proxy server to native Sliding Sync.&lt;&#x2F;strong&gt; The apps automatically detect when the homeserver supports native Sliding Sync and offers the option to migrate. If users choose to migrate, they will be prompted to log in again. This migration is optional, as the apps continue to support both native Sliding Sync and the proxy.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;November 21st: Service decommissioning.&lt;&#x2F;strong&gt; We plan to decommission the proxy service on Matrix.org and archive its codebase.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;January 17th: Element X stops supporting MSC3575.&lt;&#x2F;strong&gt; EX apps (and matrix-rust-sdk) will remove proxy support, fully shifting to native SS. The migration on EX apps will be forced. Users will get logged out so that they can log in again using native Sliding Sync. We encourage server developers to implement Sliding Sync natively by this point.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;what-this-means-for-users&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-this-means-for-users&quot; aria-label=&quot;Anchor link for: what-this-means-for-users&quot;&gt;🔗&lt;&#x2F;a&gt;What This Means for Users&lt;&#x2F;h2&gt;
&lt;p&gt;To continue enjoying the speed of Sliding Sync your homeserver and client must support the native Sliding Sync implementation (MSC4186).&lt;&#x2F;p&gt;
&lt;p&gt;At the time of writing, the latest versions of Synapse support native Sliding Sync, as do the Element X clients. There may be other server &#x2F; client implementations that also have or are in the process of adding support.
If you do use Element X apps, native Sliding Sync is used for every new login. For those currently using Element X through the proxy service, the app will prompt you to log out to switch to native Sliding Sync. While this migration is optional for now, it will become mandatory on the 21st of November for those on Matrix.org, when the proxy will be decommissioned.
Element X will discontinue support for the previous Sliding Sync implementation (MSC3575) entirely by January 17th.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;guidance-for-server-client-developers&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#guidance-for-server-client-developers&quot; aria-label=&quot;Anchor link for: guidance-for-server-client-developers&quot;&gt;🔗&lt;&#x2F;a&gt;Guidance for Server &amp;amp; Client Developers&lt;&#x2F;h2&gt;
&lt;p&gt;Server &amp;amp; Client developers are encouraged to implement MSC4186 for native sliding sync. Server developers should be aware that by the 17th of January Element clients will drop support for MSC3575, marking a transition to the native system.&lt;&#x2F;p&gt;
&lt;p&gt;We appreciate your understanding as we take this step forward for the Matrix ecosystem.&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>Type coverage for Sydent: evaluation</title>
    <published>2021-12-17T00:00:00+00:00</published>
    <updated>2021-12-17T00:00:00+00:00</updated>
    <author>
      <name>David Robertson</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2021/12/17/type-coverage-for-sydent-evaluation/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2021/12/17/type-coverage-for-sydent-evaluation/</id>
    <content type="html">&lt;p&gt;This is the third in a series of three posts which discuss recent work to improve type annotations in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&quot;&gt;Sydent&lt;&#x2F;a&gt;, the reference Matrix Identity server. &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;10&#x2F;type-coverage-for-sydent-annotation&quot;&gt;Last time&lt;&#x2F;a&gt; we discussed the mechanics of how we added type coverage. Now I want to reflect on how well we did. What information and guarantees did we gain from &lt;code&gt;mypy&lt;&#x2F;code&gt;? How could we track our progress and measure the effect of our work? And lastly, what other tools are out there apart from &lt;code&gt;mypy&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-best-parts-of-strict&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-best-parts-of-strict&quot; aria-label=&quot;Anchor link for: the-best-parts-of-strict&quot;&gt;🔗&lt;&#x2F;a&gt;The best parts of &lt;code&gt;--strict&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;While the primary goal was to improve Sydent&#x27;s coverage and robustness, to some extent this was an experiment too. How much could we get out of typing and static analysis, if we &lt;em&gt;really&lt;&#x2F;em&gt; invested in thorough annotations? Sydent is a small project that would make for a good testbed! I decided my goal would be to get Sydent passing mypy under &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#cmdoption-mypy-strict&quot;&gt;--strict mode&lt;&#x2F;a&gt;. This is a command line option which turns on a number of extra checks (though not everything); it feels similar to passing &lt;code&gt;-Wall -Wextra -Werror&lt;&#x2F;code&gt; to &lt;code&gt;gcc&lt;&#x2F;code&gt;. It&#x27;s a little extreme, but Sydent is a small project and this would be a good chance to see how hard it would be. In my view, the most useful options implied by strict mode were as follows.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;check-untyped-defs&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#check-untyped-defs&quot; aria-label=&quot;Anchor link for: check-untyped-defs&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#cmdoption-mypy-check-untyped-defs&quot;&gt;--check-untyped-defs&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;By default, mypy will only analyze the implementation of functions that are annotated. On the one hand, without annotations for inputs and the return type, it&#x27;s going to be hard for mypy to thoroughly check the soundness of your function. On the other, it can still do good work with the type information it has from other sources. Mypy can&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;infer the type of literals, e.g. deducing &lt;code&gt;x: str&lt;&#x2F;code&gt; from  &lt;code&gt;x = &quot;hello&quot;&lt;&#x2F;code&gt;;&lt;&#x2F;li&gt;
&lt;li&gt;lookup the return types of standard library calls, via &lt;code&gt;typeshed&lt;&#x2F;code&gt;; and similarly&lt;&#x2F;li&gt;
&lt;li&gt;lookup the return types of any annotated functions in your code or dependencies.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The information is already available for free: we may as well try to use it to spot problems.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;disallow-untyped-defs-and-friends&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#disallow-untyped-defs-and-friends&quot; aria-label=&quot;Anchor link for: disallow-untyped-defs-and-friends&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#cmdoption-mypy-disallow-untyped-defs&quot;&gt;--disallow-untyped-defs&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#untyped-definitions-and-calls&quot;&gt;friends&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;This flag forces you to fully annotate every function. There are less extreme versions available, e.g. &lt;code&gt;--disallow-incomplete-defs&lt;&#x2F;code&gt;; but I think this is a good option to ensure full coverage of your module. It means you can rely on mypy&#x27;s error output as a to-do list.&lt;&#x2F;p&gt;
&lt;p&gt;One downside to this: sometimes I felt like I was writing obvious boilerplate annotations, e.g.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;__str__(self) -&amp;gt; str:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There was one particular example of this that crops up a lot. Mypy has a special exception for a class&#x27;s &lt;code&gt;__init__&lt;&#x2F;code&gt; and &lt;code&gt;__init_subclass__&lt;&#x2F;code&gt; methods. If a return type annotation is missing, it will &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;issues&#x2F;604#issuecomment-348525995&quot;&gt;assume these functions return None&lt;&#x2F;a&gt; instead of &lt;code&gt;Any&lt;&#x2F;code&gt;. (See  here for &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;pull&#x2F;5677&quot;&gt;its implementation&lt;&#x2F;a&gt;.) This is normally compatible with &lt;code&gt;--disallow-untyped-defs&lt;&#x2F;code&gt; and &lt;code&gt;--disallow-incomplete-defs&lt;&#x2F;code&gt;, with one exception. If your &lt;code&gt;__init__&lt;&#x2F;code&gt; function takes no arguments other than &lt;code&gt;self&lt;&#x2F;code&gt;, mypy won&#x27;t consider it annotated, and you&#x27;ll need to write &lt;code&gt;-&amp;gt; None&lt;&#x2F;code&gt; explicitly.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s also worth mentioning &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#cmdoption-mypy-disallow-untyped-calls&quot;&gt;--disallow-untyped-calls&lt;&#x2F;a&gt;, which will cause an error if an annotated function calls an unannotated function. Again, it helps to ensure that mypy has a complete picture of the types in your function&#x27;s implementation. It also helps to highlight dependencies—if you see errors from this, it might be more practical to annotate the functions and modules it&#x27;s calling first.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;warn-return-any&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#warn-return-any&quot; aria-label=&quot;Anchor link for: warn-return-any&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#cmdoption-mypy-warn-return-any&quot;&gt;--warn-return-any&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;If I&#x27;ve written a function and annotated it to return an &lt;code&gt;int&lt;&#x2F;code&gt;, mypy will rightly complain if its implementation actually goes on to return a &lt;code&gt;str&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;foo() -&amp;gt; int:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# error: Incompatible return value type (got &amp;quot;str&amp;quot;, expected &amp;quot;int&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;hello&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If mypy isn&#x27;t sure what type I&#x27;m returning though, i.e. if I&#x27;m returning an expression of type &lt;code&gt;Any&lt;&#x2F;code&gt;, then by default mypy will trust that we&#x27;ve done the right thing.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;i_promise_this_is_an_int():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;hello&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;bar() -&amp;gt; int:
&lt;&#x2F;span&gt;&lt;span&gt;    reveal_type(i_promise_this_is_an_int()) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Any
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;i_promise_this_is_an_int()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Enabling &lt;code&gt;--warn-return-any&lt;&#x2F;code&gt; will disable this behaviour; to make this error pass we&#x27;ll have to prove to mypy that &lt;code&gt;i_promise_this_is_an_int()&lt;&#x2F;code&gt; really is an &lt;code&gt;int&lt;&#x2F;code&gt;. Sometimes that will be the case, and an extra annotation will provide the necessary proof. At other times (like in this example), investigation will prove that there really is a bug!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;strict-equality&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#strict-equality&quot; aria-label=&quot;Anchor link for: strict-equality&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#cmdoption-mypy-strict-equality&quot;&gt;--strict-equality&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;This is a bit like a limited form of gcc&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;gcc&#x2F;Warning-Options.html&quot;&gt;-Wtautological-compare&lt;&#x2F;a&gt;. Mypy will report and reject equality tests between incompatible types. If mypy can spot that an equality is always &lt;code&gt;False&lt;&#x2F;code&gt;, there&#x27;s a good chance of there being a bug in your program, or else an incorrect annotation.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m not sure how general this check is, since users can define their own types with their own rules for equality by overriding &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;reference&#x2F;datamodel.html?highlight=__eq__#object.__eq__&quot;&gt;&lt;strong&gt;eq&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;. Perhaps it only applies to built-in types?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quantifying-coverage&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#quantifying-coverage&quot; aria-label=&quot;Anchor link for: quantifying-coverage&quot;&gt;🔗&lt;&#x2F;a&gt;Quantifying coverage&lt;&#x2F;h2&gt;
&lt;p&gt;It was important to have some way to numerically evaluate our efforts to improve type coverage. It&#x27;s a fairly abstract piece of work: there&#x27;s nothing user-visible about it, unless we happen to discover a bug and fix it.&lt;&#x2F;p&gt;
&lt;p&gt;The most obvious metric is the number of total errors reported by mypy. Before the recent sprint, we had roughly 600 errors total.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;dmr on titan in sydent on  HEAD (3dde3ad) via 🐍 v3.9.7 (env)
&lt;&#x2F;span&gt;&lt;span&gt;2021-11-08 12:35:37 ✔  $ mypy --strict sydent
&lt;&#x2F;span&gt;&lt;span&gt;Found 635 errors in 59 files (checked 78 source files)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is a decent way to measure your progress when working on a particular module or package, but it&#x27;s not perfect, because the errors aren&#x27;t independent. Fixing one could fix another ten or reveal another twenty—the numeric value can be erratic.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;reports&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#reports&quot; aria-label=&quot;Anchor link for: reports&quot;&gt;🔗&lt;&#x2F;a&gt;Reports&lt;&#x2F;h3&gt;
&lt;p&gt;I found mypy&#x27;s various &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#report-generation&quot;&gt;reports&lt;&#x2F;a&gt; to be a better approach here. There were three reports I found particularly useful.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;html-report&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#html-report&quot; aria-label=&quot;Anchor link for: html-report&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;code&gt;--html-report&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;This produces a main index page showing the &quot;imprecision&quot; of each module. At the bottom of the table is a total imprecision value across the entire project.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;img&#x2F;2021-12-17-sydent-typing-html-report-index.png&quot; alt=&quot;HTML report, index page. A table showing each module&amp;#39;s precision and number of lines of code.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The precision for each module is broken down line-by-line and colour-coded accordingly, which is useful for getting an intuition for what makes a line imprecise. More on that shortly.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;img&#x2F;2021-12-17-sydent-typing-html-report-module.png&quot; alt=&quot;HTML report, module page. Most lines of source code are highlighted green; a minority are highlighted red.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;txt-report&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#txt-report&quot; aria-label=&quot;Anchor link for: txt-report&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;code&gt;--txt-report&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;This reproduces the index page from the &lt;code&gt;html&lt;&#x2F;code&gt; report as a plain text file. It&#x27;s slightly easier to parse—that&#x27;s how I got the data for the precision line graphs in &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;03&#x2F;type-coverage-for-sydent-motivation&quot;&gt;part one&lt;&#x2F;a&gt; of this series. That was a quick and dirty hack, though; a proper analysis of precision probably ought to read from the json or xml output formats. Here&#x27;s a truncated sample:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;+-----------------------------------+-------------------+----------+
&lt;&#x2F;span&gt;&lt;span&gt;| Module                            | Imprecision       | Lines    |
&lt;&#x2F;span&gt;&lt;span&gt;+-----------------------------------+-------------------+----------+
&lt;&#x2F;span&gt;&lt;span&gt;| sydent                            |   0.00% imprecise |    1 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| sydent.config                     |   0.00% imprecise |  266 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| sydent.config._base               |   0.00% imprecise |   31 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| sydent.config.crypto              |  15.94% imprecise |   69 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| ...                               |               ... |      ... |
&lt;&#x2F;span&gt;&lt;span&gt;| sydent.validators                 |   0.00% imprecise |   61 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| sydent.validators.common          |   7.35% imprecise |   68 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| sydent.validators.emailvalidator  |   1.30% imprecise |  154 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| sydent.validators.msisdnvalidator |   1.34% imprecise |  149 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;+-----------------------------------+-------------------+----------+
&lt;&#x2F;span&gt;&lt;span&gt;| Total                             |   5.95% imprecise | 9707 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;+-----------------------------------+-------------------+----------+
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;any-exprs-report&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#any-exprs-report&quot; aria-label=&quot;Anchor link for: any-exprs-report&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;code&gt;--any-exprs-report&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Selecting this option generate two reports: &lt;code&gt;any-exprs.txt&lt;&#x2F;code&gt; and &lt;code&gt;types-of-anys.txt&lt;&#x2F;code&gt;. The latter is interesting to understand where the &lt;code&gt;Anys&lt;&#x2F;code&gt; come from, but the former is more useful for quantifying the progress of typing. Another sample:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;                  Name   Anys   Exprs   Coverage
&lt;&#x2F;span&gt;&lt;span&gt;-------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;                sydent      0       2    100.00%
&lt;&#x2F;span&gt;&lt;span&gt;         sydent.config      0     185    100.00%
&lt;&#x2F;span&gt;&lt;span&gt;   sydent.config._base      0       3    100.00%
&lt;&#x2F;span&gt;&lt;span&gt;  sydent.config.crypto     34      80     57.50%
&lt;&#x2F;span&gt;&lt;span&gt;sydent.config.database      0       8    100.00%
&lt;&#x2F;span&gt;&lt;span&gt;   sydent.config.email      0      86    100.00%
&lt;&#x2F;span&gt;&lt;span&gt;                   ...    ...     ...        ...
&lt;&#x2F;span&gt;&lt;span&gt;-------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;                 Total    544   11366     95.21%
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The breakdown in &lt;code&gt;types-of-anys.txt&lt;&#x2F;code&gt; has more gory detail. I found the &quot;Unimported&quot; column particularly interesting: it lets us see how exposed we are to a lack of typing in our dependencies.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;                             Name   Unannotated   Explicit   Unimported   Omitted Generics   Error   Special Form   Implementation Artifact
&lt;&#x2F;span&gt;&lt;span&gt;-------------------------------------------------------------------------------------------------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;                           sydent             0          0            0                  0       0              0                         0
&lt;&#x2F;span&gt;&lt;span&gt;                    sydent.config             0          3            0                  0       0              0                         0
&lt;&#x2F;span&gt;&lt;span&gt;              sydent.config._base             0          0            0                  0       0              0                         0
&lt;&#x2F;span&gt;&lt;span&gt;                              ...           ...        ...          ...                ...     ...            ...                       ...
&lt;&#x2F;span&gt;&lt;span&gt;        sydent.util.versionstring             0         80            0                  0       0              0                         0
&lt;&#x2F;span&gt;&lt;span&gt;                sydent.validators             0          4            0                  0       0              0                         0
&lt;&#x2F;span&gt;&lt;span&gt;         sydent.validators.common             0         20            0                  0       0              0                         0
&lt;&#x2F;span&gt;&lt;span&gt; sydent.validators.emailvalidator             0          8            0                  0       0              0                         0
&lt;&#x2F;span&gt;&lt;span&gt;sydent.validators.msisdnvalidator             0          8            0                  0       0              0                         0
&lt;&#x2F;span&gt;&lt;span&gt;-------------------------------------------------------------------------------------------------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;                            Total             9       1276          273                  0      37              0                        17
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;the-meaning-of-precision&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-meaning-of-precision&quot; aria-label=&quot;Anchor link for: the-meaning-of-precision&quot;&gt;🔗&lt;&#x2F;a&gt;The meaning of precision&lt;&#x2F;h3&gt;
&lt;p&gt;There are two metrics I chose to focus on:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the proportion of &quot;imprecise&quot; lines across the project; I also used the complement, &lt;code&gt;precision = 100% - imprecision&lt;&#x2F;code&gt;, and&lt;&#x2F;li&gt;
&lt;li&gt;the proportion of expressions whose type is not &lt;code&gt;Any&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These are plotted in the graph at the top of this writeup. I could see that precision and the proportion of typed expressions were correlated, but I didn&#x27;t understand how they differed. I couldn&#x27;t see an explanation in the mypy docs, so I went &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;blob&#x2F;d807e097d142a88a48af93314d15ad87e41d2f19&#x2F;mypy&#x2F;stats.py&quot;&gt;digging&lt;&#x2F;a&gt; into the mypy source code. My understanding is as follows.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;There are &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;blob&#x2F;d807e097d142a88a48af93314d15ad87e41d2f19&#x2F;mypy&#x2F;stats.py#L27-L31&quot;&gt;five kinds of precision&lt;&#x2F;a&gt;. Full details are visible in the &lt;code&gt;--lineprecision-report&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Two kinds of precision, &lt;code&gt;EMPTY&lt;&#x2F;code&gt; and &lt;code&gt;UNANALYZED&lt;&#x2F;code&gt; convey no information, because there&#x27;s nothing to analyze.&lt;&#x2F;li&gt;
&lt;li&gt;A line is marked as precise, imprecise or any based on the expressions it uses.
&lt;ul&gt;
&lt;li&gt;An expression that has type &lt;code&gt;Any&lt;&#x2F;code&gt; leads to precision &lt;code&gt;ANY&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;I &lt;em&gt;think&lt;&#x2F;em&gt; an expression that &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;blob&#x2F;2907a4dea939e20ff39ef7d9ff85ae1a199a0ee8&#x2F;mypy&#x2F;stats.py#L422-L423&quot;&gt;involves &lt;code&gt;Any&lt;&#x2F;code&gt; but is not &lt;code&gt;Any&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; counts as imprecise. For instance, &lt;code&gt;Dict[str, Any]&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Remaining expressions have precision &lt;code&gt;PRECISE&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;A line&#x27;s precision is the worst of all its expressions&#x27; precisions.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ANY&lt;&#x2F;code&gt; is worse than &lt;code&gt;IMPRECISE&lt;&#x2F;code&gt;, which is worse than &lt;code&gt;PRECISE&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The &quot;imprecision&quot; number reported by mypy counts the number of lines &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;blob&#x2F;3bdef9fe6d401f3d2e0cacf4964bd315550c3394&#x2F;mypy&#x2F;xml&#x2F;mypy-txt.xslt#L77-L78&quot;&gt;classified as &lt;code&gt;IMPRECISE&lt;&#x2F;code&gt; or &lt;code&gt;ANY&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;On balance, my preferred metric is the line-level (im)precision percentage. There wasn&#x27;t much difference between the two in my experience, but the colour-coded visualisation in the HTML report is a neat feature to have. Maybe in the future there could be a version of the HTML report that colour-codes each &lt;em&gt;expression&lt;&#x2F;em&gt;?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-larger-typing-ecosystem&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-larger-typing-ecosystem&quot; aria-label=&quot;Anchor link for: the-larger-typing-ecosystem&quot;&gt;🔗&lt;&#x2F;a&gt;The larger typing ecosystem&lt;&#x2F;h2&gt;
&lt;p&gt;There are plenty of articles out there about the typing. As well as the &lt;a href=&quot;http:&#x2F;&#x2F;mypy-lang.blogspot.com&#x2F;&quot;&gt;mypy blog itself&lt;&#x2F;a&gt;, see Daniele Varrazzo&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;www.varrazzo.com&#x2F;blog&#x2F;2020&#x2F;03&#x2F;31&#x2F;first-experience-mypy&#x2F;&quot;&gt;post on &lt;code&gt;psycopg3&lt;&#x2F;code&gt; (2020)&lt;&#x2F;a&gt;, Dropbox&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;dropbox.tech&#x2F;application&#x2F;our-journey-to-type-checking-4-million-lines-of-python&quot;&gt;blog post (2019)&lt;&#x2F;a&gt;, Zulip&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;blog.zulip.com&#x2F;2016&#x2F;10&#x2F;13&#x2F;static-types-in-python-oh-mypy&#x2F;&quot;&gt;blog post (2016)&lt;&#x2F;a&gt;, Glyph&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;glyph.twistedmatrix.com&#x2F;2020&#x2F;07&#x2F;new-duck.html&quot;&gt;blog post on &lt;code&gt;Protocols&lt;&#x2F;code&gt; (2020)&lt;&#x2F;a&gt; and a follow-up &lt;a href=&quot;https:&#x2F;&#x2F;glyph.twistedmatrix.com&#x2F;2021&#x2F;03&#x2F;interfaces-and-protocols.html&quot;&gt;comparing them to &lt;code&gt;zope.interface&lt;&#x2F;code&gt; (2021)&lt;&#x2F;a&gt; and Nylas&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;www.nylas.com&#x2F;blog&#x2F;not-your-pie-mypy&#x2F;&quot;&gt;blog (2019)&lt;&#x2F;a&gt;. I&#x27;m sure there&#x27;s plenty more out there.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s worth highlighting the &lt;code&gt;typeshed&lt;&#x2F;code&gt; project, which maintains stubs for the standard library, plus popular third-party libraries. I &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;typeshed&#x2F;pull&#x2F;6150&quot;&gt;submitted a PR&lt;&#x2F;a&gt; to add a single type hint—it was a very pleasant experience! Microsoft has an &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;python-type-stubs&quot;&gt;incubator&lt;&#x2F;a&gt; of sorts for stubs too.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;other-typecheckers&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#other-typecheckers&quot; aria-label=&quot;Anchor link for: other-typecheckers&quot;&gt;🔗&lt;&#x2F;a&gt;Other typecheckers&lt;&#x2F;h3&gt;
&lt;p&gt;After the sprint to improve coverage, I spent a short amount of time trying the alternative type checkers out there. Mypy isn&#x27;t the &lt;em&gt;only&lt;&#x2F;em&gt; typechecker out there—other companies have built and open-sourced their own tools, with different strengths, weaknesses and goals. This is by no means an authoritative, exhaustive survey—just my quick notes.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;pyre-facebook&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pyre-facebook&quot; aria-label=&quot;Anchor link for: pyre-facebook&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;a href=&quot;https:&#x2F;&#x2F;pyre-check.org&#x2F;&quot;&gt;Pyre&lt;&#x2F;a&gt; (Facebook)&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;I couldn&#x27;t work out how to configure paths to resolve import errors; in the end, I wasn&#x27;t able to process much of Sydent&#x27;s source code.&lt;&#x2F;li&gt;
&lt;li&gt;Couldn&#x27;t get it to process annotations like &lt;code&gt;syd: &quot;Sydent&quot;&lt;&#x2F;code&gt; where &quot;Sydent&quot; is an import guarded by &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html?highlight=type_checking#typing.TYPE_CHECKING&quot;&gt;TYPE_CHECKING&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;No plugin system that I could see. That said, it has a separate mode&#x2F;program for running &lt;a href=&quot;https:&#x2F;&#x2F;pyre-check.org&#x2F;docs&#x2F;pysa-basics&quot;&gt;&quot;Taint Analysis&quot;&lt;&#x2F;a&gt; to spot security issues.&lt;&#x2F;li&gt;
&lt;li&gt;Seemed stricter by default compared to mypy: there was less inference of types.&lt;&#x2F;li&gt;
&lt;li&gt;Also has its own strict mode.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;pyright-microsoft&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pyright-microsoft&quot; aria-label=&quot;Anchor link for: pyright-microsoft&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;pyright&quot;&gt;Pyright&lt;&#x2F;a&gt; (Microsoft)&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Didn&#x27;t seem to recognise &lt;code&gt;getLogger&lt;&#x2F;code&gt; as being imported from &lt;code&gt;logging&lt;&#x2F;code&gt;. Not sure what happened there—maybe something wrong with its bundled version of &lt;code&gt;typeshed&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;In a few places, Sydent uses &lt;code&gt;urllib.parse.quote&lt;&#x2F;code&gt; but only imports &lt;code&gt;urllib&lt;&#x2F;code&gt;. We must be unintentionally relying on our dependencies to &lt;code&gt;import urllib.parse&lt;&#x2F;code&gt; somewhere! Mypy didn&#x27;t complain about this; pyright did.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Seemed to give a better explanations of why complex types were incompatible. For example:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;&#x2F;home&#x2F;dmr&#x2F;workspace&#x2F;sydent&#x2F;sydent&#x2F;replication&#x2F;pusher.py
&lt;&#x2F;span&gt;&lt;span&gt;   &#x2F;home&#x2F;dmr&#x2F;workspace&#x2F;sydent&#x2F;sydent&#x2F;replication&#x2F;pusher.py:77:16 - error: Expression of type &amp;quot;DeferredList&amp;quot; cannot be assigned to return type &amp;quot;Deferred[List[Tuple[bool, None]]]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;     TypeVar &amp;quot;_DeferredResultT@Deferred&amp;quot; is contravariant
&lt;&#x2F;span&gt;&lt;span&gt;       TypeVar &amp;quot;_T@list&amp;quot; is invariant
&lt;&#x2F;span&gt;&lt;span&gt;         Tuple entry 2 is incorrect type
&lt;&#x2F;span&gt;&lt;span&gt;           Type &amp;quot;None&amp;quot; cannot be assigned to type &amp;quot;_DeferredResultT@_DeferredListResultItemT&amp;quot; (reportGeneralTypeIssues)
&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;home&#x2F;dmr&#x2F;workspace&#x2F;sydent&#x2F;sydent&#x2F;sms&#x2F;openmarket.py
&lt;&#x2F;span&gt;&lt;span&gt;   &#x2F;home&#x2F;dmr&#x2F;workspace&#x2F;sydent&#x2F;sydent&#x2F;sms&#x2F;openmarket.py:93:13 - error: Argument of type &amp;quot;dict[_KT@dict, list[bytes]]&amp;quot; cannot be assigned to parameter &amp;quot;rawHeaders&amp;quot; of type &amp;quot;Mapping[AnyStr@__init__, Sequence[AnyStr@__init__]] | None&amp;quot; in function &amp;quot;__init__&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;     Type &amp;quot;dict[_KT@dict, list[bytes]]&amp;quot; cannot be assigned to type &amp;quot;Mapping[AnyStr@__init__, Sequence[AnyStr@__init__]] | None&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;       TypeVar &amp;quot;_KT@Mapping&amp;quot; is invariant
&lt;&#x2F;span&gt;&lt;span&gt;         Type &amp;quot;_KT@dict&amp;quot; is incompatible with constrained type variable &amp;quot;AnyStr&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;       Type cannot be assigned to type &amp;quot;None&amp;quot; (reportGeneralTypeIssues)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This would have been really helpful when interpreting mypy&#x27;s error reports; I&#x27;d love to see something like it in mypy.
Here&#x27;s another example where I tried running against a Synapse file.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;&#x2F;home&#x2F;dmr&#x2F;workspace&#x2F;synapse&#x2F;synapse&#x2F;storage&#x2F;databases&#x2F;main&#x2F;cache.py
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;home&#x2F;dmr&#x2F;workspace&#x2F;synapse&#x2F;synapse&#x2F;storage&#x2F;databases&#x2F;main&#x2F;cache.py:103:53 - error: Expression of type &amp;quot;list[tuple[Unknown, Tuple[Unknown, ...]]]&amp;quot; cannot be assigned to declared type &amp;quot;List[Tuple[int, _CacheData]]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  TypeVar &amp;quot;_T@list&amp;quot; is invariant
&lt;&#x2F;span&gt;&lt;span&gt;    Tuple entry 2 is incorrect type
&lt;&#x2F;span&gt;&lt;span&gt;      Tuple size mismatch; expected 3 but received indeterminate number (reportGeneralTypeIssues)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is really valuable information. It&#x27;s worth considering Pyright as an option to get a second opinion!&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;It looks like Pyright&#x27;s name for &lt;code&gt;Any&lt;&#x2F;code&gt; is &lt;code&gt;Unknown&lt;&#x2F;code&gt;. I think that does a better job of emphasising that &lt;code&gt;Unknown&lt;&#x2F;code&gt; won&#x27;t be type checked. I&#x27;d certainly be more reluctant to type &lt;code&gt;x: Unknown&lt;&#x2F;code&gt; versus &lt;code&gt;x: Any&lt;&#x2F;code&gt;!&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Pyright is the machinery behind &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;pylance-release&quot;&gt;Pylance&lt;&#x2F;a&gt;, which drives &lt;a href=&quot;https:&#x2F;&#x2F;marketplace.visualstudio.com&#x2F;items?itemName=ms-python.vscode-pylance&quot;&gt;VS Code&#x27;s Python extension&lt;&#x2F;a&gt;. That alone probably makes it worthy of more eyes.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Seemed like it was the best-placed alternative typechecker to challenge mypy (the de-facto standard).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;pytype-google&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pytype-google&quot; aria-label=&quot;Anchor link for: pytype-google&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;pytype&quot;&gt;Pytype&lt;&#x2F;a&gt; (Google)&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;Google internal? Seems to be maintained by one person semiregularly by &quot;syncing&quot; from Google.&lt;&#x2F;li&gt;
&lt;li&gt;Apparently contains a script &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;pytype&#x2F;tree&#x2F;master&#x2F;pytype&#x2F;tools&#x2F;merge_pyi&quot;&gt;merge-pyi&lt;&#x2F;a&gt; to annotate a source file given a stub file.&lt;&#x2F;li&gt;
&lt;li&gt;No support for TypedDict: as soon as it saw one in Sydent, it stopped all analysis.&lt;&#x2F;li&gt;
&lt;li&gt;No Python 3.10 support (according to the README anyway).&lt;&#x2F;li&gt;
&lt;li&gt;I think it might use a different kind of typing semantics; its &lt;a href=&quot;https:&#x2F;&#x2F;google.github.io&#x2F;pytype&#x2F;typing_faq.html&quot;&gt;typing FAQ&lt;&#x2F;a&gt; speaks of &quot;descriptive typing&quot; and a more lenient approach.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;pycharm&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pycharm&quot; aria-label=&quot;Anchor link for: pycharm&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.jetbrains.com&#x2F;pycharm&#x2F;&quot;&gt;PyCharm&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;PyCharm has its own means to typechecking code as you write it. It&#x27;s definitely caught bugs before, and having the instant feedback as you type is really nice! I have seen it struggle with &lt;code&gt;zope.interface&lt;&#x2F;code&gt; and some uses of &lt;code&gt;Generic&lt;&#x2F;code&gt;s though.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;runtime-uses-of-annotations&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#runtime-uses-of-annotations&quot; aria-label=&quot;Anchor link for: runtime-uses-of-annotations&quot;&gt;🔗&lt;&#x2F;a&gt;Runtime uses of annotations&lt;&#x2F;h3&gt;
&lt;p&gt;When annotations &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;dev&#x2F;peps&#x2F;pep-3107&#x2F;&quot;&gt;were first introduced&lt;&#x2F;a&gt;, they were a generic means to associate Python objects with parts of a program. (It was only later that the community agreed that we really want to use them to annotate &lt;em&gt;types&lt;&#x2F;em&gt;). These annotations are available at runtime in the &lt;code&gt;__annotations__&lt;&#x2F;code&gt; attribute. There&#x27;s also a helper function in &lt;code&gt;typing&lt;&#x2F;code&gt; which will help resolve forward references.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;get_type_hints
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;foo(x: int) -&amp;gt; str: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;pass
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; get_type_hints(foo)
&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;x&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;int&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;return&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;str&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Programs and libraries are free to use these annotations at runtime as they see fit. The most well-known examples are probably &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;dataclasses.html&quot;&gt;dataclasses&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.attrs.org&#x2F;en&#x2F;stable&#x2F;&quot;&gt;attrs&lt;&#x2F;a&gt; with &lt;a href=&quot;https:&#x2F;&#x2F;www.attrs.org&#x2F;en&#x2F;stable&#x2F;types.html&quot;&gt;auto_attribs=True&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;pydantic-docs.helpmanual.io&#x2F;&quot;&gt;Pydantic&lt;&#x2F;a&gt;. I&#x27;d be interested to learn if anyone else is consuming annotations at runtime!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;🔗&lt;&#x2F;a&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;All in all, in a two-week sprint we were able to get Sydent&#x27;s mypy coverage from a precision of 83% up to 94%. Our work would have spotted the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;415&quot;&gt;bytes-versus-strings bug&lt;&#x2F;a&gt;; we understand why &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;413&quot;&gt;the missing await&lt;&#x2F;a&gt; wasn&#x27;t detected. We &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;419&quot;&gt;fixed&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;449&quot;&gt;other&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;447&quot;&gt;small&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;445&quot;&gt;bugs&lt;&#x2F;a&gt; too as part of the process. As well as fix bugs, I&#x27;ve hopefully made the source code clearer for future readers (but that one is hard to quantify).&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s room to spin out contributions upstream too. I submitted &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;twisted&#x2F;twisted&#x2F;pull&#x2F;1669&quot;&gt;two&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;twisted&#x2F;twisted&#x2F;pull&#x2F;1668&quot;&gt;PRs&lt;&#x2F;a&gt; to twisted upstream; have started to work on annotations for &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pyca&#x2F;pynacl&#x2F;pull&#x2F;693&quot;&gt;pynacl&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pyca&#x2F;pynacl&#x2F;pull&#x2F;694&quot;&gt;in my&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pyca&#x2F;pynacl&#x2F;pull&#x2F;695&quot;&gt;spare time&lt;&#x2F;a&gt;; and submitted a quick fix to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;typeshed&#x2F;pull&#x2F;6150&quot;&gt;typeshed&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Looking forward, I think we&#x27;d get a quick gain from ensuring that our smaller libraries (&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;python-signedjson&quot;&gt;signedjson&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;python-canonicaljson&quot;&gt;canonicaljson&lt;&#x2F;a&gt;) are annotated. We&#x27;ll be sticking with mypy for now—the &lt;code&gt;mypy-zope&lt;&#x2F;code&gt; plugin is crucial given our reliance on twisted. We&#x27;re also working to improve Sygnal and Synapse—though not to the extreme standard of &lt;code&gt;--strict&lt;&#x2F;code&gt; across everything.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;d say the biggest outstanding hole is our processing of JSON objects. There&#x27;s too much &lt;code&gt;Dict[str, Any]&lt;&#x2F;code&gt; flying around. The ideal for me would be to define &lt;code&gt;dataclass&lt;&#x2F;code&gt; or &lt;code&gt;attr.s&lt;&#x2F;code&gt; class &lt;code&gt;C&lt;&#x2F;code&gt;, and be able to deserialise a JSON object to &lt;code&gt;C&lt;&#x2F;code&gt;, including automatic (deep) type checking. &lt;a href=&quot;https:&#x2F;&#x2F;pydantic-docs.helpmanual.io&#x2F;&quot;&gt;Pydantic&lt;&#x2F;a&gt; sounds really close to what we want, but I&#x27;m told it will by default gladly interpret the json string &lt;code&gt;&quot;42&quot;&lt;&#x2F;code&gt; as the Python integer &lt;code&gt;42&lt;&#x2F;code&gt;, which isn&#x27;t what we&#x27;d like. More investigation needed there. There are other avenues to explore too, like &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;erickpeirson&#x2F;jsonschema-typed&quot;&gt;jsonschema-typed&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;pypi.org&#x2F;project&#x2F;typedload&#x2F;&quot;&gt;typedload&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bloomberg&#x2F;attrs-strict&quot;&gt;attrs-strict&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To end, I&#x27;d like to add a few personal thoughts. Having types available in the source code is definitely A Good Thing. But there is a part of me that wonders if it might have been worth writing our projects in a language which incorporates types from day one. There are always trade-offs, of course: runtime performance, build times, iteration speed, ease of onboarding new contributors, ease of deployment, availability of libraries, ability to shoot yourself in the foot... the list goes on.&lt;&#x2F;p&gt;
&lt;p&gt;On a more upbeat note, adding typing is a great way to get familiar with new source code. It involves a mixture of reading, cross-referencing, deduction, analysis, all across a wide variety of files. It&#x27;d be a &lt;em&gt;lot&lt;&#x2F;em&gt; easier to type as you write from the get-go, but typing after the fact is still a worthy use of time and effort.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Many thanks for reading! If you&#x27;ve got any corrections, comments or queries, I&#x27;m available on Matrix at &lt;a href=&quot;https:&#x2F;&#x2F;matrix.to&#x2F;#&#x2F;@dmrobertson:matrix.org&quot;&gt;@dmrobertson:matrix.org&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>Type coverage for Sydent: annotation</title>
    <published>2021-12-10T00:00:00+00:00</published>
    <updated>2021-12-10T00:00:00+00:00</updated>
    <author>
      <name>David Robertson</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2021/12/10/type-coverage-for-sydent-annotation/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2021/12/10/type-coverage-for-sydent-annotation/</id>
    <content type="html">&lt;p&gt;This is the second in a series of three posts which discuss recent work to improve type annotations in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&quot;&gt;Sydent&lt;&#x2F;a&gt;, the reference Matrix Identity server. &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;03&#x2F;type-coverage-for-sydent-motivation&quot;&gt;Last time&lt;&#x2F;a&gt; we discussed the motivation for doing this work in the first place: the &lt;em&gt;why&lt;&#x2F;em&gt;. Now I want to talk about the &lt;em&gt;how&lt;&#x2F;em&gt;. How did we add annotations to individual files, and across the project as whole? What common idioms did we learn on the way?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-process-of-improving-coverage&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-process-of-improving-coverage&quot; aria-label=&quot;Anchor link for: the-process-of-improving-coverage&quot;&gt;🔗&lt;&#x2F;a&gt;The process of improving coverage&lt;&#x2F;h2&gt;
&lt;p&gt;From experience adding typing to Synapse, we decided to annotate one module at a time. We configured a list of files in &lt;code&gt;pyproject.toml&lt;&#x2F;code&gt; which we knew passed mypy&#x27;s checks. We could run &lt;code&gt;mypy&lt;&#x2F;code&gt; in CI to check that new PRs didn&#x27;t introduce type problems in modules already covered.&lt;&#x2F;p&gt;
&lt;p&gt;From there, the workflow was&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Choose a new module to annotate. Add it to the list of &lt;code&gt;files&lt;&#x2F;code&gt; in mypy&#x27;s configuration.&lt;&#x2F;li&gt;
&lt;li&gt;Run &lt;code&gt;mypy&lt;&#x2F;code&gt;. See how many errors you get.&lt;&#x2F;li&gt;
&lt;li&gt;Choose an error. Fix it. Re-run &lt;code&gt;mypy&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Repeat until no errors remaining.&lt;&#x2F;li&gt;
&lt;li&gt;Submit for review.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;There are two parts in there which involve a choice. Being honest, I made those choices unscientifically: I tried to choose the easy tasks to do first. My first target was actually the entire &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;418&quot;&gt;sydent.util&lt;&#x2F;a&gt; subpackage. Probably a bit too large for a first bite! My thinking was that &lt;code&gt;util&lt;&#x2F;code&gt; sounded like something with few dependencies that would have impact across the whole source tree.&lt;&#x2F;p&gt;
&lt;p&gt;Within a given module, I&#x27;d try to fix easier errors first: partly for confidence, partly to build up momentum, and partly to get myself familiar with that piece of source code. For example, I&#x27;d often start by telling mypy that &lt;code&gt;mylist = []&lt;&#x2F;code&gt; was actually was a &lt;code&gt;List[str]&lt;&#x2F;code&gt; (rather than the generic &lt;code&gt;List[Any]&lt;&#x2F;code&gt; which it would use otherwise).&lt;&#x2F;p&gt;
&lt;p&gt;Picking and choosing easy targets works fairly well, but sometimes that means you end up fixing an error that&#x27;s really a symptom of an earlier one. Other times fixing one error, e.g. by giving a return type annotation to a function—would solve a series of other errors throughout the file. Watching the total number of errors mypy reports bob up and down was intriguing!&lt;&#x2F;p&gt;
&lt;p&gt;In retrospect, I think it would be smoother to generate some kind of dependency graph for the package. I&#x27;m imagining a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Directed_acyclic_graph&quot;&gt;DAG&lt;&#x2F;a&gt; where whose vertices are modules, and there&#x27;s an edge &lt;code&gt;A -&amp;gt; B&lt;&#x2F;code&gt; if &lt;code&gt;A&lt;&#x2F;code&gt; imports from &lt;code&gt;B&lt;&#x2F;code&gt;. The sinks of this DAG (i.e. modules which don&#x27;t depend on any others in the package) are the ideal place to start: you can get something strictly typechecked there without having to annotate a long chain of dependencies across other files. Another strategy would be to see which modules were the least precise according to mypy&#x27;s reports—but more on those &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;17&#x2F;type-coverage-for-sydent-evaluation&quot;&gt;next time&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;you-re-at-the-mercy-of-your-dependencies&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#you-re-at-the-mercy-of-your-dependencies&quot; aria-label=&quot;Anchor link for: you-re-at-the-mercy-of-your-dependencies&quot;&gt;🔗&lt;&#x2F;a&gt;You&#x27;re at the mercy of your dependencies&lt;&#x2F;h3&gt;
&lt;p&gt;I think this is my single biggest takeaway from the process of adding annotations to Sydent.
I&#x27;ll admit the phrasing is melodramatic, but I think it rings true.&lt;&#x2F;p&gt;
&lt;p&gt;Improving coverage boils down to giving the typechecker more information about your program. The more information it has, the more it can check—and the more errors it can spot. (Hopefully this doesn&#x27;t make typing come across like a pyramid scheme.) If your dependencies aren&#x27;t typed, mypy can&#x27;t validate you&#x27;re correctly providing inputs and correctly consuming outputs. You might have a bigger impact on overall typing coverage by annotating a dependency (directly or via stubs). I have a hunch that bugs are more likely in code that uses an external dependency: we&#x27;re much more familiar with the details of our own source code compared to that of a third party we trust.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s worth looking to see if your dependencies have a newer version including type annotations. Failing that, they may have a stub package added to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;typeshed&#x2F;tree&#x2F;master&#x2F;stubs&quot;&gt;typeshed&lt;&#x2F;a&gt; and published on PyPI. I saw example of both cases when choosing how to configure mypy for Sydent. If some of your dependencies are under your control, consider annotating them—you&#x27;ll feel the benefits across multiple projects pretty quickly.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;annotations-when-working-with-twisted&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#annotations-when-working-with-twisted&quot; aria-label=&quot;Anchor link for: annotations-when-working-with-twisted&quot;&gt;🔗&lt;&#x2F;a&gt;Annotations when working with twisted&lt;&#x2F;h3&gt;
&lt;p&gt;Twisted is Sydent&#x27;s biggest dependency, and I certainly felt at its mercy! In particular, it has a few quirks which make it trickier to annotate applications using it. Here&#x27;s a summary of the work we had to do to get those annotations working.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;partially-typed-modules-and-stubs&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#partially-typed-modules-and-stubs&quot; aria-label=&quot;Anchor link for: partially-typed-modules-and-stubs&quot;&gt;🔗&lt;&#x2F;a&gt;Partially typed modules and stubs&lt;&#x2F;h4&gt;
&lt;p&gt;Early into the process, mypy reported that calling the function &lt;a href=&quot;https:&#x2F;&#x2F;twistedmatrix.com&#x2F;documents&#x2F;current&#x2F;api&#x2F;twisted.python.log.html#err&quot;&gt;twisted.python.log.err&lt;&#x2F;a&gt; was an error. It did so because I was running mypy in &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#cmdoption-mypy-strict&quot;&gt;--strict mode&lt;&#x2F;a&gt;. We&#x27;ll talk more about why I did so and what this means &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;17&#x2F;type-coverage-for-sydent-evaluation&quot;&gt;next time&lt;&#x2F;a&gt;; for now, it&#x27;s enough to know that calling a function that isn&#x27;t fully annotated from within a function that is constitutes an error under strict mode. &lt;code&gt;twisted&lt;&#x2F;code&gt; is partially annotated: many key modules and functions have type annotations, but others don&#x27;t. I was reluctant to give up on &lt;code&gt;--strict&lt;&#x2F;code&gt;. Instead, I decided to stub the &lt;code&gt;err&lt;&#x2F;code&gt; function myself.&lt;&#x2F;p&gt;
&lt;p&gt;A stub is a cut-down version of a python function, class or module which lives in a &lt;code&gt;.pyi&lt;&#x2F;code&gt; file. All implementation details are removed; only type annotations remain. Stubs are useful when you want to write annotations for code you don&#x27;t control. The &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;typeshed&quot;&gt;typeshed&lt;&#x2F;a&gt; library is probably the best example: a collection of third party stubs for the standard library, plus some popular third party packages. Microsoft&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;python-type-stubs&quot;&gt;python-type-stubs&lt;&#x2F;a&gt; is another example. They&#x27;d also solve the problem I mentioned at the end of the &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;03&#x2F;type-coverage-for-sydent-motivation&quot;&gt;first part&lt;&#x2F;a&gt;: I could use a stub to &lt;em&gt;teach&lt;&#x2F;em&gt; mypy that &lt;code&gt;IResponse.headers&lt;&#x2F;code&gt; was a &lt;code&gt;Headers&lt;&#x2F;code&gt; object.&lt;&#x2F;p&gt;
&lt;p&gt;Writing a stub for &lt;code&gt;log.err&lt;&#x2F;code&gt; was straightforward, thanks mainly to Twisted&#x27;s thorough documentation. I chose to write it by hand, rather than use &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;stubgen.html&quot;&gt;stubgen&lt;&#x2F;a&gt;. I&#x27;d heard of the latter, but was reluctant to use it for a few reasons.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Twisted is a big project with many big files. I didn&#x27;t want to commit huge stub files for me and my colleagues to maintain.&lt;&#x2F;li&gt;
&lt;li&gt;The more our stubs cover, the larger the risk of a stub becoming out-of-date with twisted itself. Upstream twisted is the best place for these annotations.&lt;&#x2F;li&gt;
&lt;li&gt;We only need annotations for the bits of twisted that we&#x27;re using.&lt;&#x2F;li&gt;
&lt;li&gt;And, being honest: I wanted the low-level experience of writing stubs, cross-referencing between the source and working how to best capture its type semantics.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I think this decision to write a targeted stub made sense at the time. After all, &lt;code&gt;twisted.python.logging.err&lt;&#x2F;code&gt; is just one simple function! But for the project as a whole, I regret not using &lt;code&gt;stubgen&lt;&#x2F;code&gt; to generate module-level stubs. The reason for this is that a &lt;code&gt;.pyi&lt;&#x2F;code&gt; stub file accounts for an entire module: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;issues&#x2F;5880#issuecomment-439237176&quot;&gt;no more and no less&lt;&#x2F;a&gt;. This means that the stubs I was writing for parts of twisted only covered the functions and classes I&#x27;d stubbed. Any existing annotations in the twisted source code would be ignored, along with any types that mypy was able to infer for itself.&lt;&#x2F;p&gt;
&lt;p&gt;I think it would have been more efficient to use &lt;code&gt;stubgen&lt;&#x2F;code&gt; to generate stubs and patch them up, rather than writing them. That would have helped avoid a few cases I encountered where stubbing one function would cause additional typechecking failures (because mypy was no longer examining the twisted source for that file). It would also have meant that I could just faithfully stub Twisted as it is; in practice, I would sometimes hesitate to stub to avoid having to cover another module. &lt;code&gt;sydent.http&lt;&#x2F;code&gt; was the most painful part of the source tree for this: that&#x27;s where we make the most use of Twisted.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;defer-inlinecallbacks&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#defer-inlinecallbacks&quot; aria-label=&quot;Anchor link for: defer-inlinecallbacks&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;a href=&quot;https:&#x2F;&#x2F;twistedmatrix.com&#x2F;documents&#x2F;current&#x2F;api&#x2F;twisted.internet.defer.html#inlineCallbacks&quot;&gt;defer.inlineCallbacks&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;This is a decorator which allows us to write code in the style of &lt;code&gt;async&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;await&lt;&#x2F;code&gt; without actually using that syntax. (Twisted predates &lt;code&gt;asyncio&lt;&#x2F;code&gt; and the &lt;code&gt;async&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;await&lt;&#x2F;code&gt; syntax, introduced in Python 3.4 and 3.5 respectively. It was originally released in 2002, back when Python had released version 2.2.) We only use it in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;blob&#x2F;e4b4dbbdf25255d19effceae7061ad9b3eefc374&#x2F;sydent&#x2F;http&#x2F;matrixfederationagent.py#L125-L132&quot;&gt;one place in Sydent&lt;&#x2F;a&gt; nowadays, but I&#x27;ve seen used across Synapse too. I mention it here because it was a bit fiddly to annotate. Here&#x27;s its use in Sydent:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;    @defer.inlineCallbacks
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;request(
&lt;&#x2F;span&gt;&lt;span&gt;        self,
&lt;&#x2F;span&gt;&lt;span&gt;        method: bytes,
&lt;&#x2F;span&gt;&lt;span&gt;        uri: bytes,
&lt;&#x2F;span&gt;&lt;span&gt;        headers: Optional[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Headers&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        bodyProducer: Optional[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;IBodyProducer&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    ) -&amp;gt; Generator[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;defer.Deferred[Any]&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, Any, IResponse]:
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here, &lt;code&gt;request&lt;&#x2F;code&gt; is a &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;glossary.html#term-generator&quot;&gt;generator function&lt;&#x2F;a&gt; because its body uses the &lt;code&gt;yield&lt;&#x2F;code&gt; keyword. Yielding allows the function to relinquish control back to twisted&#x27;s reactor, only for its execution to be resumed asynchronously in the future. The &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html?highlight=typing%20generator#typing.Generator&quot;&gt;Generator&lt;&#x2F;a&gt; type takes three parameters:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;YieldType&lt;&#x2F;code&gt;, &lt;code&gt;Deferred[Any]&lt;&#x2F;code&gt;;&lt;&#x2F;li&gt;
&lt;li&gt;a &lt;code&gt;SendType&lt;&#x2F;code&gt;, &lt;code&gt;Any&lt;&#x2F;code&gt;; and&lt;&#x2F;li&gt;
&lt;li&gt;a &lt;code&gt;ReturnType&lt;&#x2F;code&gt;, &lt;code&gt;IResponse&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Why have I opted to use &lt;code&gt;Any&lt;&#x2F;code&gt; here, when we&#x27;ve seen (and will see) that this limits mypy&#x27;s ability to run checks? The answer is that we yield two different types within the function. Firstly a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;blob&#x2F;e4b4dbbdf25255d19effceae7061ad9b3eefc374&#x2F;sydent&#x2F;http&#x2F;matrixfederationagent.py#L152-L153&quot;&gt;routing result&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;        routing: _RoutingResult
&lt;&#x2F;span&gt;&lt;span&gt;        routing = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;yield &lt;&#x2F;span&gt;&lt;span&gt;defer.ensureDeferred(self._route_matrix_uri(parsed_uri))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and later, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;blob&#x2F;e4b4dbbdf25255d19effceae7061ad9b3eefc374&#x2F;sydent&#x2F;http&#x2F;matrixfederationagent.py#L194-L195&quot;&gt;the IResponse&lt;&#x2F;a&gt; we go on to return:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;        res: IResponse
&lt;&#x2F;span&gt;&lt;span&gt;        res = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;yield &lt;&#x2F;span&gt;&lt;span&gt;agent.request(method, uri, headers, bodyProducer)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In this example:&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;We yield a value &lt;code&gt;y: Deferred[Any]&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;That will later be resolved by twisted to an &lt;code&gt;x: Any&lt;&#x2F;code&gt; value. Twisted will send that value to &lt;code&gt;request&lt;&#x2F;code&gt;, and the execution continues.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;This repeats, until we eventually return an &lt;code&gt;IResponse&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I could more correctly annotate the &lt;code&gt;YieldType&lt;&#x2F;code&gt; as &lt;code&gt;Deferred[Union[_RoutingResult, IResponse]]&lt;&#x2F;code&gt; so that the &lt;code&gt;SendType&lt;&#x2F;code&gt; was &lt;code&gt;Union[_RoutingResult, IResponse]&lt;&#x2F;code&gt;. But this would mean we end up having some kind of type check at each yield point: a &lt;code&gt;cast&lt;&#x2F;code&gt;, or a &lt;code&gt;type: ignore&lt;&#x2F;code&gt;, or a runtime &lt;code&gt;isinstance&lt;&#x2F;code&gt; check. It didn&#x27;t feel like it was worth the boilerplate, especially since I could narrow e.g. &lt;code&gt;res: Any&lt;&#x2F;code&gt; to &lt;code&gt;res: IResponse&lt;&#x2F;code&gt; with minimal effort.&lt;&#x2F;p&gt;
&lt;p&gt;This problem doesn&#x27;t arise with using the &lt;code&gt;async&#x2F;await&lt;&#x2F;code&gt; syntax:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;async def &lt;&#x2F;span&gt;&lt;span&gt;foo() -&amp;gt; int:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;async def &lt;&#x2F;span&gt;&lt;span&gt;bar() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    x = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span&gt;foo()
&lt;&#x2F;span&gt;&lt;span&gt;    reveal_type(foo())
&lt;&#x2F;span&gt;&lt;span&gt;    reveal_type(x)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ mypy example.py
&lt;&#x2F;span&gt;&lt;span&gt;example.py:6: note: Revealed type is &amp;quot;typing.Coroutine[Any, Any, builtins.int]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;example.py:7: note: Revealed type is &amp;quot;builtins.int*&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Behind the scenes, I &lt;em&gt;think&lt;&#x2F;em&gt; that &lt;code&gt;x = await foo()&lt;&#x2F;code&gt; is really using the same mechanism as the &lt;code&gt;inlineCallbacks&lt;&#x2F;code&gt; approach.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;async def&lt;&#x2F;code&gt; function is really a generator function behind the scenes.&lt;&#x2F;li&gt;
&lt;li&gt;When we &lt;code&gt;await foo()&lt;&#x2F;code&gt;, we yield the expression &lt;code&gt;foo()&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Then the machinery running our coroutine &lt;code&gt;c&lt;&#x2F;code&gt; will call &lt;code&gt;c.send(x)&lt;&#x2F;code&gt; to resume execution, where &lt;code&gt;x&lt;&#x2F;code&gt; is the value produced by waiting for &lt;code&gt;foo()&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;With the &lt;code&gt;await&lt;&#x2F;code&gt; form, mypy knows two things:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the value &lt;code&gt;foo()&lt;&#x2F;code&gt; which was yielded should be &lt;code&gt;Awaitable[T]&lt;&#x2F;code&gt;, and&lt;&#x2F;li&gt;
&lt;li&gt;the value &lt;code&gt;x&lt;&#x2F;code&gt; send to the coroutine should come from awaiting &lt;code&gt;foo()&lt;&#x2F;code&gt;, and therefore be of type &lt;code&gt;T&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Mypy can&#x27;t assume or enforce these rules for the yield form, which can yield and send whatever it likes. There&#x27;s no reason why the send type should be related to the yield type. Here&#x27;s a toy example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;Any, Dict, Generator
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;generator_function() -&amp;gt; Generator[int, str, Dict[str, Any]]:
&lt;&#x2F;span&gt;&lt;span&gt;  y: int = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;10
&lt;&#x2F;span&gt;&lt;span&gt;  x: str = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;yield &lt;&#x2F;span&gt;&lt;span&gt;y
&lt;&#x2F;span&gt;&lt;span&gt;  print(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Coroutine was sent&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, x)  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# -&amp;gt; Coroutine was sent hello
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;got&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;done&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;coroutine = generator_function()
&lt;&#x2F;span&gt;&lt;span&gt;y = next(coroutine)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  coroutine.send(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;hello&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;except &lt;&#x2F;span&gt;&lt;span&gt;StopIteration &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;e:
&lt;&#x2F;span&gt;&lt;span&gt;  return_value = e.value
&lt;&#x2F;span&gt;&lt;span&gt;  print(return_value)  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# -&amp;gt; {&amp;#39;got&amp;#39;: &amp;#39;hello&amp;#39;, &amp;#39;done&amp;#39;: True}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;All in all, the handling of &lt;code&gt;inlineCallbacks&lt;&#x2F;code&gt; is a situation specific to working with (older?) twisted code. It&#x27;s still nice to understand what&#x27;s going on behind the scenes though!&lt;&#x2F;p&gt;
&lt;h4 id=&quot;zope-interface-interface&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zope-interface-interface&quot; aria-label=&quot;Anchor link for: zope-interface-interface&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;code&gt;zope.interface.Interface&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Twisted makes use of &lt;code&gt;zope&lt;&#x2F;code&gt;&#x27;s &lt;code&gt;Interface&lt;&#x2F;code&gt; to define a number of abstract interface classes. Speaking personally, I&#x27;ve not seen it used outside twisted, and I think that means it&#x27;s not supported by much of the typechecking tooling. For example, I&#x27;ve definitely seen PyCharm struggle to realise that it&#x27;s okay to pass a &lt;code&gt;Response&lt;&#x2F;code&gt; to a function which expects an &lt;code&gt;IResponse&lt;&#x2F;code&gt;! Here&#x27;s a more complicated example where &lt;code&gt;PyCharm&lt;&#x2F;code&gt; isn&#x27;t happy with me widening the type &lt;code&gt;LoggingHostnameEndpoint&lt;&#x2F;code&gt; to &lt;code&gt;IStreamClientEndpoint&lt;&#x2F;code&gt;, even though &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;blob&#x2F;92ff7a878a25696365b10cc49e32f5cba32c5960&#x2F;sydent&#x2F;http&#x2F;matrixfederationagent.py#L379-L380&quot;&gt;the latter implements the former&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;img&#x2F;2021-12-10-pycharm-false-positive.png&quot; alt=&quot;Screenshot from pycharm showing a false positive warning&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Mypy out of the box doesn&#x27;t play well with a zope &lt;code&gt;Interface&lt;&#x2F;code&gt; (nor does any other typechecker I tried). Fortunately, the excellent &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Shoobx&#x2F;mypy-zope&quot;&gt;mypy-zope&lt;&#x2F;a&gt; plugin helps here: it teaches mypy that any class like &lt;code&gt;Response&lt;&#x2F;code&gt; which &lt;code&gt;@implements(IResponse)&lt;&#x2F;code&gt;  can be passed in place of an &lt;code&gt;IResponse&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tricks-of-the-trade&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#tricks-of-the-trade&quot; aria-label=&quot;Anchor link for: tricks-of-the-trade&quot;&gt;🔗&lt;&#x2F;a&gt;Tricks of the trade&lt;&#x2F;h3&gt;
&lt;p&gt;At this point I&#x27;d like to share a few generic lessons about typing I&#x27;d picked up. Nothing ground-breaking here: I think these are all fairly well-known. Hopefully they&#x27;re the start of a good cheat sheet for annotating—though it pales in comparison to the &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;cheat_sheet_py3.html&quot;&gt;Mypy cheat sheet&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;annotating-decorators&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#annotating-decorators&quot; aria-label=&quot;Anchor link for: annotating-decorators&quot;&gt;🔗&lt;&#x2F;a&gt;Annotating decorators&lt;&#x2F;h4&gt;
&lt;p&gt;Annotating decorators is fiddly, but it&#x27;s also vitally important. An unannotated decorator will mask or throw away your decoratee&#x27;s annotations! The way to write the annotation is best explained by the &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;generics.html#declaring-decorators&quot;&gt;mypy docs&lt;&#x2F;a&gt;, but briefly: it involves a &lt;code&gt;TypeVar&lt;&#x2F;code&gt; and sometimes a &lt;code&gt;cast&lt;&#x2F;code&gt; too. Here&#x27;s an example.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;TypeVar, Callable, Any, cast
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;F = TypeVar(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;F&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, bound=Callable[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;, Any])
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;decorator(input: F) -&amp;gt; F:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;wrapped(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;args: Any, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs: Any) -&amp;gt; Any:
&lt;&#x2F;span&gt;&lt;span&gt;        print(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Calling &lt;&#x2F;span&gt;&lt;span&gt;{f.__name__}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;input_func(*args, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;cast(F, wrapped)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The idea here is&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;Callable[..., Any]&lt;&#x2F;code&gt; to describe a generic function with no particular signature.&lt;&#x2F;li&gt;
&lt;li&gt;Use that as a bound on a type variable &lt;code&gt;F&lt;&#x2F;code&gt;. At each usage of &lt;code&gt;@decorator&lt;&#x2F;code&gt;, mypy will deduce a more specific version of &lt;code&gt;F&lt;&#x2F;code&gt;, e.g. &lt;code&gt;Callable[[int], str]&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Within that usage of &lt;code&gt;@decorator&lt;&#x2F;code&gt;, &lt;code&gt;F&lt;&#x2F;code&gt; is fixed to that specific type. We use &lt;code&gt;-&amp;gt; F&lt;&#x2F;code&gt; to express that &quot;we return a function with the same signature as the decoratee&quot;.&lt;&#x2F;li&gt;
&lt;li&gt;Unfortunately, we don&#x27;t have a good way to tell &lt;code&gt;mypy&lt;&#x2F;code&gt; that &lt;code&gt;wrapped&lt;&#x2F;code&gt; also has that signature &lt;code&gt;F&lt;&#x2F;code&gt;. We resort to a &lt;code&gt;cast&lt;&#x2F;code&gt; to force mypy to accept this without proof.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This might change in the future, e.g. when &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html?highlight=paramspec#typing.ParamSpec&quot;&gt;ParamSpec&lt;&#x2F;a&gt; is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;issues&#x2F;8645&quot;&gt;fully understood&lt;&#x2F;a&gt; by mypy.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;prefer-object-over-any&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#prefer-object-over-any&quot; aria-label=&quot;Anchor link for: prefer-object-over-any&quot;&gt;🔗&lt;&#x2F;a&gt;Prefer &lt;code&gt;object&lt;&#x2F;code&gt; over &lt;code&gt;Any&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Both of these are general types for expressing &quot;I don&#x27;t know anything about this expression&quot;. But only the former will undergo static type checks. We want those type checks to guard against bugs accidentally introduced in the future. For instance, imagine a class with an &lt;code&gt;Any&lt;&#x2F;code&gt; attribute.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;Any
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;dataclasses
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@dataclasses.dataclass
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;C:
&lt;&#x2F;span&gt;&lt;span&gt;    label: Any
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Imagine in the future we add a new method which assumes that &lt;code&gt;label&lt;&#x2F;code&gt; is a string:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;greeting(self) -&amp;gt; str:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;My name is &amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;+ self.label
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Mypy will consider this valid, because no type-checking is done on an &lt;code&gt;Any&lt;&#x2F;code&gt; value. It will complain that it can&#x27;t prove that &lt;code&gt;greeting&lt;&#x2F;code&gt; returns a &lt;code&gt;str&lt;&#x2F;code&gt;, if &lt;code&gt;--warn-return-any&lt;&#x2F;code&gt; is enabled; but putting that aside, it can&#x27;t identify the call site as a bug. The bug slips through to runtime.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;C(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;123&lt;&#x2F;span&gt;&lt;span&gt;).greeting()  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# TypeError: can only concatenate str (not &amp;quot;int&amp;quot;) to str
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Replacing the &lt;code&gt;Any&lt;&#x2F;code&gt; with &lt;code&gt;object&lt;&#x2F;code&gt; does allow mypy to spot the problem.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;error: Unsupported operand types for + (&amp;quot;str&amp;quot; and &amp;quot;object&amp;quot;)  [operator]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;type-ignore-and-cast-sparingly&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#type-ignore-and-cast-sparingly&quot; aria-label=&quot;Anchor link for: type-ignore-and-cast-sparingly&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;code&gt;# type: ignore&lt;&#x2F;code&gt; and &lt;code&gt;cast&lt;&#x2F;code&gt; sparingly&lt;&#x2F;h4&gt;
&lt;p&gt;There&#x27;s a good chance that mypy knows better than we do, so we should only overrule it if there&#x27;s no better option. There are two techniques for this. One option is to tell mypy to just silence the error, by appending a &lt;code&gt;# type: ignore&lt;&#x2F;code&gt; comment to the erroneous line. The other is to force it to accept that a certain expression has a given type: that&#x27;s what &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html?highlight=paramspec#typing.cast&quot;&gt;cast&lt;&#x2F;a&gt; is for.&lt;&#x2F;p&gt;
&lt;p&gt;I never like using either of these, but sometimes they&#x27;re the most practical choice. I&#x27;d recommend two best practices for their use, however:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Only ignore a specific error code, e.g. &lt;code&gt;# type: ignore[assignment]&lt;&#x2F;code&gt;.  Those codes can be displayed by passing &lt;code&gt;--show-error-codes&lt;&#x2F;code&gt; to mypy.&lt;&#x2F;li&gt;
&lt;li&gt;Leave a comment before every &lt;code&gt;#type: ignore[...]&lt;&#x2F;code&gt; and every &lt;code&gt;cast&lt;&#x2F;code&gt; to justify their correctness. I don&#x27;t think this is a widely-held practice. I picked it up from the Rust world, where it&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;rust-lang.github.io&#x2F;api-guidelines&#x2F;documentation.html#function-docs-include-error-panic-and-safety-considerations-c-failure&quot;&gt;encouraged&lt;&#x2F;a&gt; as a way to justify &lt;code&gt;unsafe&lt;&#x2F;code&gt; source code.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h4 id=&quot;there-s-good-stuff-in-typing&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#there-s-good-stuff-in-typing&quot; aria-label=&quot;Anchor link for: there-s-good-stuff-in-typing&quot;&gt;🔗&lt;&#x2F;a&gt;There&#x27;s good stuff in &lt;code&gt;typing&lt;&#x2F;code&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;It&#x27;s worth a read through the &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html&quot;&gt;module documentation&lt;&#x2F;a&gt;—plenty of things in there I wish I&#x27;d known about sooner. There&#x27;s lots in the toolkit to chose from. Some bits I use fairly often include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html?highlight=typing%20protocol#typing.Protocol&quot;&gt;Protocol&lt;&#x2F;a&gt;: lets you formalise duck typing. To use it, define a class that inherits from &lt;code&gt;Protocol&lt;&#x2F;code&gt;. Its methods and attributes are all stubs which describe what you require of objects belonging to this type. It&#x27;s like an &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;abc.html?highlight=abc#module-abc&quot;&gt;abstract base class&lt;&#x2F;a&gt; or interface, but purely at typecheck time.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html?highlight=typing%20generic#typing.Generic&quot;&gt;Generic&lt;&#x2F;a&gt;: define your own generic types. A bit of a slippery slope to type mania!&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html?highlight=typing%20generic#typing.Optional&quot;&gt;Optional&lt;&#x2F;a&gt;: I use this all the time. It&#x27;s always good to make your &lt;code&gt;None&lt;&#x2F;code&gt;s explicit!&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html?highlight=typing%20generic#typing.NewType&quot;&gt;NewType&lt;&#x2F;a&gt;: I haven&#x27;t had a chance to use it much. As I understand it, it&#x27;s a way to define a &quot;strong typedef&quot;. For example, we can use it to distinguish lengths from durations, even if they&#x27;re both represented by a &lt;code&gt;float&lt;&#x2F;code&gt; at runtime.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I want to call out two parts of &lt;code&gt;typing&lt;&#x2F;code&gt; in particular:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;overload&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#overload&quot; aria-label=&quot;Anchor link for: overload&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html?highlight=typing%20generic#typing.overload&quot;&gt;overload&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;code&gt;overload&lt;&#x2F;code&gt; is a way to provide extra information about a function depending on how it&#x27;s called. For instance, consider this function which takes a &lt;code&gt;str&lt;&#x2F;code&gt; or &lt;code&gt;bytes&lt;&#x2F;code&gt; as input and returns its uppercase version.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;upper(x: Union[bytes, str]) -&amp;gt; Union[bytes, str]:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;x.upper()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The problem with this annotation is that we&#x27;ll have to check at every call site to see if the return value was a &lt;code&gt;bytes&lt;&#x2F;code&gt; or a &lt;code&gt;str&lt;&#x2F;code&gt; object. But we know that uppercasing a &lt;code&gt;str&lt;&#x2F;code&gt; gives us a &lt;code&gt;str&lt;&#x2F;code&gt;, and uppercasing a &lt;code&gt;bytes&lt;&#x2F;code&gt; gives us a &lt;code&gt;bytes.&lt;&#x2F;code&gt; We can use &lt;code&gt;overload&lt;&#x2F;code&gt; to express this.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;overload
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@overload
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;upper(x: str) -&amp;gt; str: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@overload
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;upper(x: bytes) -&amp;gt; bytes: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;upper(x: Union[bytes, str]) -&amp;gt; Union[bytes, str]:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;x.upper()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first two &lt;code&gt;@overload&lt;&#x2F;code&gt; definitions are like stubs: they&#x27;re purely used for their annotations. The actual runtime implementation is specified at the end, undecorated. (&lt;strong&gt;NB&lt;&#x2F;strong&gt;: this specific example is better expressed without overloads, by using &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html?highlight=typing%20generic#typing.AnyStr&quot;&gt;AnyStr&lt;&#x2F;a&gt;.)&lt;&#x2F;p&gt;
&lt;p&gt;I was really impressed to see how &lt;code&gt;mypy&lt;&#x2F;code&gt; could use this overloading information. Here&#x27;s an example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;overload, Literal
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@overload
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;f(x: int) -&amp;gt; Literal[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@overload
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;f(x: str) -&amp;gt; Literal[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;f(x: object) -&amp;gt; int:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;isinstance(x, int):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;elif &lt;&#x2F;span&gt;&lt;span&gt;isinstance(x, str):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;f(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;) == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    print(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;potato&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can see that &lt;code&gt;f(10) == 1&lt;&#x2F;code&gt; and so the equality is always &lt;code&gt;False&lt;&#x2F;code&gt;: we&#x27;ll never print the word &quot;potato&quot;. Mypy can reason through this too, if we ask it nicely.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ mypy example.py
&lt;&#x2F;span&gt;&lt;span&gt;Success: no issues found in 1 source file
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$ mypy --strict-equality --warn-unreachable example.py
&lt;&#x2F;span&gt;&lt;span&gt;example.py:16: error: Non-overlapping equality check (left operand type: &amp;quot;Literal[1]&amp;quot;, right operand type: &amp;quot;Literal[2]&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;example.py:17: error: Statement is unreachable
&lt;&#x2F;span&gt;&lt;span&gt;Found 2 errors in 1 file (checked 1 source file)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;typeddict&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typeddict&quot; aria-label=&quot;Anchor link for: typeddict&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html?highlight=typeddict#typing.TypedDict&quot;&gt;TypedDict&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;I mentioned this &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;03&#x2F;type-coverage-for-sydent-motivation&quot;&gt;in last week&#x27;s post&lt;&#x2F;a&gt;) when talking about the missing &lt;code&gt;await&lt;&#x2F;code&gt; bug.
Subclassing from &lt;code&gt;TypedDict&lt;&#x2F;code&gt; allows us to define a new type whose values are dictionaries with&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;a fixed set of keys (some mandatory, some not), and&lt;&#x2F;li&gt;
&lt;li&gt;a fixed type for each key&#x27;s value.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;dev&#x2F;peps&#x2F;pep-0589&#x2F;&quot;&gt;PEP 589&lt;&#x2F;a&gt; can best describe the motivation, but in short: there&#x27;s a lot of source code out there that passes dictionaries around. &lt;code&gt;TypedDict&lt;&#x2F;code&gt; is a way to gradually add typechecking to that code, without having to refactor it to use e.g. a &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;dataclasses.html&quot;&gt;dataclass&lt;&#x2F;a&gt; or a &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html#typing.NamedTuple&quot;&gt;NamedTuple&lt;&#x2F;a&gt;. Let&#x27;s have a quick example.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;List, TypedDict
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Person(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;TypedDict&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    full_name: str
&lt;&#x2F;span&gt;&lt;span&gt;    nicknames: List[str]
&lt;&#x2F;span&gt;&lt;span&gt;    age: int
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;p: Person = {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;full_name&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;David Matthew Robertson&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nicknames&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;dmr&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;age&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;29&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Mypy will detect if you delete or omit a required key, or if you insert a key that&#x27;s not part of the type.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# error: Key &amp;quot;age&amp;quot; of TypedDict &amp;quot;Person&amp;quot; cannot be deleted
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;del &lt;&#x2F;span&gt;&lt;span&gt;p[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;age&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# error: Missing keys (&amp;quot;full_name&amp;quot;, &amp;quot;nicknames&amp;quot;, &amp;quot;age&amp;quot;) for TypedDict &amp;quot;Person&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;p2: Person = {}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# error: TypedDict &amp;quot;Person&amp;quot; has no key &amp;quot;eye_colour&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;p[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;eye_colour&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;brown&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;TypedDict&lt;&#x2F;code&gt; is a useful tool, but there are a few important gotchas to be aware of. In my view, these are all minor and worth putting up with, to benefit from the extra type information that a &lt;code&gt;TypedDict&lt;&#x2F;code&gt; provides. Let&#x27;s take a look.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;typeddict-is-incompatible-with-dict&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typeddict-is-incompatible-with-dict&quot; aria-label=&quot;Anchor link for: typeddict-is-incompatible-with-dict&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;code&gt;TypedDict&lt;&#x2F;code&gt; is incompatible with &lt;code&gt;Dict&lt;&#x2F;code&gt;&lt;&#x2F;h5&gt;
&lt;p&gt;This one surprised me at first. Why can&#x27;t I pass my &lt;code&gt;TypedDict&lt;&#x2F;code&gt; to a function that accepts a generic dictionary?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;json
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;Dict, TypedDict
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Foo(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;TypedDict&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    bar: str
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;print_size(d: Dict[object, object]) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    print(len(d))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;f: Foo = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;bar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;baz&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# error: Argument 1 to &amp;quot;print_size&amp;quot; has incompatible type &amp;quot;Foo&amp;quot;; expected &amp;quot;Dict[object, object]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;print_size(f)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The answer is that it wouldn&#x27;t be type-safe! For all we know, the function &lt;code&gt;print_size&lt;&#x2F;code&gt; might mutate its argument &lt;code&gt;d&lt;&#x2F;code&gt;. It might add a key, remove a key, or change the type of a value. Each of those would break the contract that &lt;code&gt;TypedDict&lt;&#x2F;code&gt; is supposed to enforce, so mypy is correct to flag this as an error. &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;issues&#x2F;4976&quot;&gt;This GitHub issue&lt;&#x2F;a&gt; has more discussion.&lt;&#x2F;p&gt;
&lt;p&gt;There are few workarounds for this kind of problem.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The function might be able to accept a &lt;code&gt;TypedDict&lt;&#x2F;code&gt; directly.&lt;&#x2F;li&gt;
&lt;li&gt;The function could accept a &lt;code&gt;Mapping&lt;&#x2F;code&gt; instead of a &lt;code&gt;Dict&lt;&#x2F;code&gt;. This is type-safe because the &lt;code&gt;Mapping&lt;&#x2F;code&gt; type does not offer mutating methods such as &lt;code&gt;pop&lt;&#x2F;code&gt;, &lt;code&gt;__setitem__&lt;&#x2F;code&gt;, &lt;code&gt;__del__&lt;&#x2F;code&gt;; but it only works if the function does not mutate the dictionary.&lt;&#x2F;li&gt;
&lt;li&gt;A more drastic approach would discard the &lt;code&gt;TypedDict&lt;&#x2F;code&gt; information with a &lt;code&gt;cast&lt;&#x2F;code&gt; to &lt;code&gt;Dict[str, object]&lt;&#x2F;code&gt; or similar. If so, I&#x27;d strongly recommend a comment explaining why the cast is correct and safe.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h5 id=&quot;mixing-mandatory-and-required-fields&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#mixing-mandatory-and-required-fields&quot; aria-label=&quot;Anchor link for: mixing-mandatory-and-required-fields&quot;&gt;🔗&lt;&#x2F;a&gt;Mixing mandatory and required fields&lt;&#x2F;h5&gt;
&lt;p&gt;Secondly, defining a &lt;code&gt;TypedDict&lt;&#x2F;code&gt; with a mixture of optional and required keys is a little fiddly. All keys can be made optional by passing &lt;code&gt;total=False&lt;&#x2F;code&gt; in the class definition. To have some keys optional and others mandatory, we have to make &lt;em&gt;two&lt;&#x2F;em&gt; TypedDicts. Say for instance we wanted to allow a potentially-missing &lt;code&gt;favourite_colour&lt;&#x2F;code&gt; field to &lt;code&gt;Person&lt;&#x2F;code&gt;. We can&#x27;t add an annotation &lt;code&gt;favourite_colour: Optional[str]&lt;&#x2F;code&gt; to the first class body. That&#x27;s optional in a different sense: it would mean that &lt;code&gt;favourite_colour&lt;&#x2F;code&gt; is a mandatory field which is allowed to be &lt;code&gt;None&lt;&#x2F;code&gt;. Instead, we apply &lt;code&gt;total=False&lt;&#x2F;code&gt; to a subclass:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;List, TypedDict
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;_PersonRequired(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;TypedDict&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    full_name: str
&lt;&#x2F;span&gt;&lt;span&gt;    nicknames: List[str]
&lt;&#x2F;span&gt;&lt;span&gt;    age: int
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Person(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;_PersonRequired&lt;&#x2F;span&gt;&lt;span&gt;, total=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    favourite_colour: str
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This means that a valid &lt;code&gt;Person&lt;&#x2F;code&gt; dictionary may have no &lt;code&gt;favourite_colour&lt;&#x2F;code&gt; key. If it is present, it must be a &lt;code&gt;str&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The syntax is unfortunately a little clunky. &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;dev&#x2F;peps&#x2F;pep-0655&#x2F;&quot;&gt;PEP 655&lt;&#x2F;a&gt; acknowledges this and proposes an alternative.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;typeddict-is-typecheck-time-only&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#typeddict-is-typecheck-time-only&quot; aria-label=&quot;Anchor link for: typeddict-is-typecheck-time-only&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;code&gt;TypedDict&lt;&#x2F;code&gt; is typecheck-time only&lt;&#x2F;h5&gt;
&lt;p&gt;One final note: a &lt;code&gt;TypedDict&lt;&#x2F;code&gt; does no validation or conversion whatsoever. If mypy can&#x27;t know the keys and values a dictionary will have a typecheck-time, you&#x27;ll need to validate it by hand at runtime. We see this a lot because when deserialising json objects into a dictionary. Here&#x27;s an example.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;json
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;TypedDict
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Foo(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;TypedDict&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    bar: str
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# note: Revealed type is &amp;quot;Any&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;reveal_type(json.loads(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# no error. mypy can&amp;#39;t do analysis on Any.
&lt;&#x2F;span&gt;&lt;span&gt;f: Foo = json.loads(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;next-time&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#next-time&quot; aria-label=&quot;Anchor link for: next-time&quot;&gt;🔗&lt;&#x2F;a&gt;Next time&lt;&#x2F;h2&gt;
&lt;p&gt;This covers a lot of the machinery and the day-to-day process of annotating Sydent. The &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;17&#x2F;type-coverage-for-sydent-evaluation&quot;&gt;last part of this series&lt;&#x2F;a&gt; will give us a chance to quantify our efforts and reflect on the wider typing ecosystem.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Many thanks for reading! If you&#x27;ve got any corrections, comments or queries, I&#x27;m available on Matrix at &lt;a href=&quot;https:&#x2F;&#x2F;matrix.to&#x2F;#&#x2F;@dmrobertson:matrix.org&quot;&gt;@dmrobertson:matrix.org&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>Type coverage for Sydent: motivation</title>
    <published>2021-12-03T00:00:00+00:00</published>
    <updated>2021-12-03T00:00:00+00:00</updated>
    <author>
      <name>David Robertson</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2021/12/03/type-coverage-for-sydent-motivation/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2021/12/03/type-coverage-for-sydent-motivation/</id>
    <content type="html">&lt;p&gt;&lt;em&gt;This is the first of three posts on improving type coverage in Sydent. Join us next Friday for the &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;10&#x2F;type-coverage-for-sydent-annotation&quot;&gt;second part&lt;&#x2F;a&gt;!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&quot;&gt;Sydent&lt;&#x2F;a&gt; is the reference Matrix Identity server. It provides a &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;docs&#x2F;spec&#x2F;identity_service&#x2F;r0.3.0&quot;&gt;lookup service&lt;&#x2F;a&gt;, so that you can find a Matrix user via their email address or phone number (if they&#x27;ve chosen to share it).&lt;&#x2F;p&gt;
&lt;p&gt;We recently worked on &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;414&quot;&gt;improving Sydent&#x27;s type coverage&lt;&#x2F;a&gt;: the proportion of its source code with explicit annotations denoting the kind of data that each variable, expression and return value is expected to hold. These annotations are optional, but if present, they allow tools like &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;&quot;&gt;mypy&lt;&#x2F;a&gt; to analyze your programs and spot entire classes of bugs &lt;em&gt;before&lt;&#x2F;em&gt; you ship them! In this instance, we aimed to make Sydent pass &lt;code&gt;mypy --strict&lt;&#x2F;code&gt;, which &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;commit&#x2F;7bdaac2774840e1f9697d30515f367c5c8c16866&quot;&gt;it now does&lt;&#x2F;a&gt;. Here&#x27;s what the process looked like:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;img&#x2F;TWGXKTFpjYxlbnHRkZFAzljQ.png&quot; alt=&quot;Coverage as measured by mypy. Precision and the number of typed expressions increase over the latter half of 2021.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Two lines show two different measures of how well-typed the project is. The grey region covers our two-week sprint towards improving coverage; the earliest data point is from just before previous efforts to improve typing earlier in the year.&lt;&#x2F;p&gt;
&lt;p&gt;In a series of posts, I&#x27;d like to reflect on this sprint and share what we&#x27;ve learned. In particular, I aim to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;explain why we wanted to improve type coverage &lt;em&gt;now&lt;&#x2F;em&gt;;&lt;&#x2F;li&gt;
&lt;li&gt;work through examples to see how (if?) mypy could have spotted bugs;&lt;&#x2F;li&gt;
&lt;li&gt;describe the annotation process;&lt;&#x2F;li&gt;
&lt;li&gt;illustrate common patterns I learned along the way;&lt;&#x2F;li&gt;
&lt;li&gt;discuss the checks that &lt;code&gt;mypy&lt;&#x2F;code&gt; provides; and finally&lt;&#x2F;li&gt;
&lt;li&gt;reflect on the state of Python&#x27;s typing ecosystem.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In this first part, we&#x27;ll concentrate on the first two topics; the &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;10&#x2F;type-coverage-for-sydent-annotation&quot;&gt;second&lt;&#x2F;a&gt; covers the middle two; and the &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;17&#x2F;type-coverage-for-sydent-evaluation&quot;&gt;third&lt;&#x2F;a&gt; the last two.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-do-this-now&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-do-this-now&quot; aria-label=&quot;Anchor link for: why-do-this-now&quot;&gt;🔗&lt;&#x2F;a&gt;Why do this now?&lt;&#x2F;h2&gt;
&lt;p&gt;It took us a long time (too long) to notice that the Sydent instance serving &lt;code&gt;matrix.org&lt;&#x2F;code&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;element-web&#x2F;issues&#x2F;19317&quot;&gt;was failing to send SMS messages for verification&lt;&#x2F;a&gt;. We suspected that something was going wrong with our &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;blob&#x2F;main&#x2F;sydent&#x2F;sms&#x2F;openmarket.py&quot;&gt;API call to OpenMarket&lt;&#x2F;a&gt;. Our first step was to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;410&quot;&gt;improve logging&lt;&#x2F;a&gt;, so we could start to deduce what was going wrong and why. Whilst trawling through logs, we spotted &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;413#pullrequestreview-775154313&quot;&gt;one problem&lt;&#x2F;a&gt; which meant we weren&#x27;t actually sending off the API request in the first place. Further investigation revealed a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;415&quot;&gt;strings-versus-bytes confusion&lt;&#x2F;a&gt; which meant that we would always (incorrectly) interpret the API response as having failed.&lt;&#x2F;p&gt;
&lt;p&gt;All in all, phone number verification was unknowingly broken in the 2.4.0 release, to be fixed in 2.4.6 a month later. How could we do better? Better test coverage is (as ever) one answer. But &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;413#pullrequestreview-775154313&quot;&gt;it struck me&lt;&#x2F;a&gt; that the two bugs we&#x27;d encountered might be ripe for automatic detection:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;we created an &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html#typing.Awaitable&quot;&gt;Awaitable&lt;&#x2F;a&gt; but didn&#x27;t &lt;code&gt;await&lt;&#x2F;code&gt; it or use it in any way, and&lt;&#x2F;li&gt;
&lt;li&gt;we tried to look up a &lt;code&gt;str&lt;&#x2F;code&gt; key in a dictionary which mapped &lt;code&gt;bytes&lt;&#x2F;code&gt; to &lt;code&gt;bytes&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Could a static analysis tool like &lt;code&gt;mypy&lt;&#x2F;code&gt; detect these? How much work would it take to do so? Are there other bugs and problems we could spot with it? I was curious to answer these questions and learn more about the tools that Python&#x27;s typing ecosystem provides.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;could-typing-have-spotted-these-problems&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#could-typing-have-spotted-these-problems&quot; aria-label=&quot;Anchor link for: could-typing-have-spotted-these-problems&quot;&gt;🔗&lt;&#x2F;a&gt;Could typing have spotted these problems?&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s start with the first of question: what can &lt;code&gt;mypy&lt;&#x2F;code&gt; detect?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-missing-await&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-missing-await&quot; aria-label=&quot;Anchor link for: the-missing-await&quot;&gt;🔗&lt;&#x2F;a&gt;The missing &lt;code&gt;await&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Instead of writing &lt;code&gt;x = await foo()&lt;&#x2F;code&gt;, we simply had &lt;code&gt;x = foo()&lt;&#x2F;code&gt; and didn&#x27;t then go on to &lt;code&gt;await x&lt;&#x2F;code&gt;. Mypy doesn&#x27;t have means to detect this at present. There was interest in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;issues&#x2F;2499&quot;&gt;this issue&lt;&#x2F;a&gt; on such a feature, with related threads &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;issues&#x2F;5597&quot;&gt;here&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&#x2F;issues&#x2F;5650&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Are there other opportunities to spot the error? Here&#x27;s the relevant bit of source code from &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;blob&#x2F;2e3b7576b17e92080319e08c0c0ebf566935636c&#x2F;sydent&#x2F;http&#x2F;servlets&#x2F;msisdnservlet.py#L93-L98&quot;&gt;before the fix&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;            sid = self.sydent.validators.msisdn.requestToken(
&lt;&#x2F;span&gt;&lt;span&gt;                phone_number_object, clientSecret, sendAttempt, brand
&lt;&#x2F;span&gt;&lt;span&gt;            )
&lt;&#x2F;span&gt;&lt;span&gt;            resp = {
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;success&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;sid&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: str(sid),
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;msisdn&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: msisdn,
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;intl_fmt&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: intl_fmt,
&lt;&#x2F;span&gt;&lt;span&gt;            }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The call to &lt;code&gt;requestToken&lt;&#x2F;code&gt; produces a value of type &lt;code&gt;Awaitable[int]&lt;&#x2F;code&gt;. If we tried to assign that to an expression of type &lt;code&gt;int&lt;&#x2F;code&gt; we&#x27;d get an error that mypy can spot.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ cat example.py
&lt;&#x2F;span&gt;&lt;span&gt;async def foo() -&amp;gt; int:
&lt;&#x2F;span&gt;&lt;span&gt;    return 1
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async def bar():
&lt;&#x2F;span&gt;&lt;span&gt;    x = foo()      # no error
&lt;&#x2F;span&gt;&lt;span&gt;    y: int = foo() # error: rhs is Awaitable[int], but lhs expects int
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$ mypy --check-untyped-defs example.py
&lt;&#x2F;span&gt;&lt;span&gt;example.py:6: error: Incompatible types in assignment (expression has type &amp;quot;Coroutine[Any, Any, int]&amp;quot;, variable has type &amp;quot;int&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;Found 1 error in 1 file (checked 1 source file)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that we have to specifically ask mypy to typecheck the body of &lt;code&gt;bar&lt;&#x2F;code&gt; by passing &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#cmdoption-mypy-check-untyped-defs&quot;&gt;--check-untyped-defs&lt;&#x2F;a&gt;; by default, &lt;code&gt;mypy&lt;&#x2F;code&gt; will only typecheck annotated code.&lt;&#x2F;p&gt;
&lt;p&gt;We might also have been able to detect the error by looking at how we used &lt;code&gt;sid&lt;&#x2F;code&gt;. Unfortunately, the only use of was in a conversion &lt;code&gt;str(sid)&lt;&#x2F;code&gt;, which is a perfectly type-safe call for both &lt;code&gt;sid: int&lt;&#x2F;code&gt; and &lt;code&gt;sid: Awaitable[int]&lt;&#x2F;code&gt;. But let&#x27;s put that aside for a second—suppose we added &lt;code&gt;&quot;sid&quot;: sid&lt;&#x2F;code&gt; directly into the &lt;code&gt;resp&lt;&#x2F;code&gt; dictionary. Could mypy have spotted there was a problem with &lt;em&gt;that&lt;&#x2F;em&gt;?&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately not. Because &lt;code&gt;resp&lt;&#x2F;code&gt; has no annotation, we have to rely on how it&#x27;s used to spot any type inconsistencies. There&#x27;s only one use of &lt;code&gt;resp&lt;&#x2F;code&gt;: as the return value from its enclosing function, &lt;code&gt;render_POST&lt;&#x2F;code&gt;. Mypy&#x27;s only chance to spot a type problem would be to compare the mypy&#x27;s inferred type for &lt;code&gt;resp&lt;&#x2F;code&gt; to the return type of &lt;code&gt;render_POST&lt;&#x2F;code&gt;. What are those types? We can use &lt;code&gt;reveal_type&lt;&#x2F;code&gt; to see the former is &lt;code&gt;Dict[str, object]&lt;&#x2F;code&gt;. For the latter:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;    @jsonwrap
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;render_POST(self, request: Request) -&amp;gt; JsonDict:
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The return type is &lt;code&gt;JsonDict&lt;&#x2F;code&gt;, which is an &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;blob&#x2F;2e3b7576b17e92080319e08c0c0ebf566935636c&#x2F;sydent&#x2F;types.py#L17&quot;&gt;alias&lt;&#x2F;a&gt; for &lt;code&gt;Dict[str, Any]&lt;&#x2F;code&gt;. This is bad news, because &lt;code&gt;Dict[str, object]&lt;&#x2F;code&gt; and &lt;code&gt;Dict[str, Any]&lt;&#x2F;code&gt; are compatible. Digging a level deeper, this is because &lt;code&gt;sid: Any&lt;&#x2F;code&gt; holds true for both &lt;code&gt;sid: int&lt;&#x2F;code&gt; and &lt;code&gt;sid: Awaitable[int]&lt;&#x2F;code&gt;—so there&#x27;s no error to spot here. The &lt;code&gt;Any&lt;&#x2F;code&gt; type is compatible with any other type whatsoever! Mypy uses &lt;code&gt;Any&lt;&#x2F;code&gt; as a way to &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;kinds_of_types.html#the-any-type&quot;&gt;defer all type checking to runtime&lt;&#x2F;a&gt;; mypy won&#x27;t (and can&#x27;t!) statically analyse the usage of an expression of type &lt;code&gt;Any&lt;&#x2F;code&gt;. Indeed, mypy&#x27;s reports will tell you how many &lt;code&gt;Any&lt;&#x2F;code&gt;s you&#x27;re working with, and offer a variety of options to &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#disallow-dynamic-typing&quot;&gt;warn or error on usages of &lt;code&gt;Any&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If we were inserting &lt;code&gt;sid&lt;&#x2F;code&gt; directly into a dictionary, we could do better by annotating the dictionary (or the function&#x27;s return type) as a &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html#typing.TypedDict&quot;&gt;TypedDict&lt;&#x2F;a&gt;. This is a way to specify a dictionary with a fixed set of keys, each with a fixed type. It comes in really handy for Sydent, Sygnal and Synapse—all of &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;docs&#x2F;spec&#x2F;&quot;&gt;the Matrix APIs&lt;&#x2F;a&gt; exchange JSON dictionaries, so anything we can do to teach mypy about their shape and types is gold dust.&lt;&#x2F;p&gt;
&lt;p&gt;In short, there were options for detecting this with some code changes, but no magic wand that would have spotted the error in the code as written.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-strings-bytes-confusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-strings-bytes-confusion&quot; aria-label=&quot;Anchor link for: the-strings-bytes-confusion&quot;&gt;🔗&lt;&#x2F;a&gt;The strings&#x2F;bytes confusion&lt;&#x2F;h3&gt;
&lt;p&gt;Our &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;415&#x2F;files#diff-4b3e0551612818927c87fe0100262ec230e0342def9d3f09214b93dea3efacb8L103-R107&quot;&gt;error&lt;&#x2F;a&gt; was here:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;        headers = dict(resp.headers.getAllRawHeaders())
&lt;&#x2F;span&gt;&lt;span&gt;        request_id = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;X-Request-Id&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;headers:
&lt;&#x2F;span&gt;&lt;span&gt;            request_id = headers[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;X-Request-Id&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this sample, &lt;code&gt;resp.headers&lt;&#x2F;code&gt; is a &lt;a href=&quot;https:&#x2F;&#x2F;twistedmatrix.com&#x2F;documents&#x2F;current&#x2F;api&#x2F;twisted.web.http_headers.Headers.html&quot;&gt;twisted.web.http_headers.Headers&lt;&#x2F;a&gt; instance. &lt;code&gt;getAllRawHeaders&lt;&#x2F;code&gt; is &lt;a href=&quot;https:&#x2F;&#x2F;twistedmatrix.com&#x2F;documents&#x2F;current&#x2F;api&#x2F;twisted.web.http_headers.Headers.html#getAllRawHeaders&quot;&gt;documented&lt;&#x2F;a&gt; as returning an iterable of &lt;code&gt;(bytes, Sequence[bytes])&lt;&#x2F;code&gt; pairs. Even better, mypy can see this because &lt;code&gt;getAllRawHeaders&lt;&#x2F;code&gt; is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;twisted&#x2F;twisted&#x2F;blob&#x2F;5c24e99e671c4082a1ddc8dbeb869402294bd0dc&#x2F;src&#x2F;twisted&#x2F;web&#x2F;http_headers.py#L261&quot;&gt;annotated&lt;&#x2F;a&gt; (many thanks to the twisted authors for this). Mypy should be able to deduce that we build a dictionary &lt;code&gt;headers: Dict[bytes, Sequence[bytes]&lt;&#x2F;code&gt;. We can check this using &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;cheat_sheet_py3.html#when-you-re-puzzled-or-when-things-are-complicated&quot;&gt;&lt;code&gt;reveal_type&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;        headers = dict(resp.headers.getAllRawHeaders())
&lt;&#x2F;span&gt;&lt;span&gt;        reveal_type(headers)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ mypy
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:110: note: Revealed type is &amp;quot;builtins.dict[builtins.bytes*, typing.Sequence*[builtins.bytes]]&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(The &lt;code&gt;*&lt;&#x2F;code&gt; in &lt;code&gt;builtins.bytes*&lt;&#x2F;code&gt; here means mypy has &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;50499509&#x2F;5252017&quot;&gt;inferred&lt;&#x2F;a&gt; that the dictionary&#x27;s keys are bytes, rather than being told explicitly that they must be bytes.)&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s all fine and dandy. But why didn&#x27;t we spot this before if the annotations were all in place in twisted? Let&#x27;s put aside the fact that, erm, we weren&#x27;t running mypy in Sydent&#x27;s CI &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;416&quot;&gt;until the recent sprint&lt;&#x2F;a&gt;, unlike our &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;blob&#x2F;5640992d176a499204a0756b1677c9b1575b0a49&#x2F;.github&#x2F;workflows&#x2F;tests.yml#L21&quot;&gt;other&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sygnal&#x2F;blob&#x2F;4a7367e84476a4b1054b1fe20e9e06f9f66e27f8&#x2F;.github&#x2F;workflows&#x2F;pipeline.yml#L18-L26&quot;&gt;projects&lt;&#x2F;a&gt;. Checking out the problematic version, we can run mypy on the file we know to contain the bug.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ git checkout v2.4.0
&lt;&#x2F;span&gt;&lt;span&gt;$ mypy --strict sydent&#x2F;sms&#x2F;openmarket.py
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:82: error: Dict entry 0 has incompatible type &amp;quot;str&amp;quot;: &amp;quot;int&amp;quot;; expected &amp;quot;str&amp;quot;: &amp;quot;str&amp;quot;  [dict-item]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Huh. Mypy spots something, but not the error we were hoping for. What&#x27;s going on here? We can ask mypy to show its working with &lt;code&gt;reveal_type&lt;&#x2F;code&gt; again.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;        resp = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span&gt;self.http_cli.post_json_get_nothing(
&lt;&#x2F;span&gt;&lt;span&gt;            API_BASE_URL, send_body, {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;headers&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: req_headers}
&lt;&#x2F;span&gt;&lt;span&gt;        )
&lt;&#x2F;span&gt;&lt;span&gt;        reveal_type(resp)
&lt;&#x2F;span&gt;&lt;span&gt;        headers = dict(resp.headers.getAllRawHeaders())
&lt;&#x2F;span&gt;&lt;span&gt;        reveal_type(resp.headers)
&lt;&#x2F;span&gt;&lt;span&gt;        reveal_type(resp.headers.getAllwRawHeaders())
&lt;&#x2F;span&gt;&lt;span&gt;        reveal_type(headers)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This yields:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ mypy sydent&#x2F;sms&#x2F;openmarket.py
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:82: error: Dict entry 0 has incompatible type &amp;quot;str&amp;quot;: &amp;quot;int&amp;quot;; expected &amp;quot;str&amp;quot;: &amp;quot;str&amp;quot;  [dict-item]
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:102: note: Revealed type is &amp;quot;twisted.web.iweb.IResponse*&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:104: note: Revealed type is &amp;quot;Any&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:105: note: Revealed type is &amp;quot;Any&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:106: note: Revealed type is &amp;quot;builtins.dict[Any, Any]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;Found 1 error in 1 file (checked 1 source file)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ahh, the &lt;code&gt;Any&lt;&#x2F;code&gt; type. As mentioned above, this represents a value whose type can&#x27;t be statically determined. We&#x27;re left to runtime checks to detect the problem. But we won&#x27;t detect it at runtime, because dictionaries don&#x27;t enforce any kind of type requirements on their keys and values.&lt;&#x2F;p&gt;
&lt;p&gt;The problem here is that mypy can&#x27;t see that &lt;code&gt;resp.headers&lt;&#x2F;code&gt; is a twisted &lt;code&gt;Headers&lt;&#x2F;code&gt; object. If we could inform it of this, mypy would spot our bug:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;twisted.web.http_headers
&lt;&#x2F;span&gt;&lt;span&gt;        raw_headers: twisted.web.http_headers.Headers = resp.headers
&lt;&#x2F;span&gt;&lt;span&gt;        reveal_type(resp)
&lt;&#x2F;span&gt;&lt;span&gt;        headers = dict(raw_headers.getAllRawHeaders())
&lt;&#x2F;span&gt;&lt;span&gt;        reveal_type(raw_headers)
&lt;&#x2F;span&gt;&lt;span&gt;        reveal_type(raw_headers.getAllRawHeaders())
&lt;&#x2F;span&gt;&lt;span&gt;        reveal_type(headers)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ mypy sydent&#x2F;sms&#x2F;openmarket.py
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:82: error: Dict entry 0 has incompatible type &amp;quot;str&amp;quot;: &amp;quot;int&amp;quot;; expected &amp;quot;str&amp;quot;: &amp;quot;str&amp;quot;  [dict-item]
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:104: note: Revealed type is &amp;quot;twisted.web.iweb.IResponse*&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:106: note: Revealed type is &amp;quot;twisted.web.http_headers.Headers&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:107: note: Revealed type is &amp;quot;typing.Iterator[Tuple[builtins.bytes, typing.Sequence[builtins.bytes]]]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:108: note: Revealed type is &amp;quot;builtins.dict[builtins.bytes*, typing.Sequence*[builtins.bytes]]&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:114: error: Invalid index type &amp;quot;str&amp;quot; for &amp;quot;Dict[bytes, Sequence[bytes]]&amp;quot;; expected type &amp;quot;bytes&amp;quot;  [index]
&lt;&#x2F;span&gt;&lt;span&gt;sydent&#x2F;sms&#x2F;openmarket.py:114: error: Argument 1 to &amp;quot;split&amp;quot; of &amp;quot;bytes&amp;quot; has incompatible type &amp;quot;str&amp;quot;; expected &amp;quot;Optional[bytes]&amp;quot;  [arg-type]
&lt;&#x2F;span&gt;&lt;span&gt;Found 3 errors in 1 file (checked 1 source file)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There it is, on line 114: &lt;code&gt;Invalid index type &quot;str&quot; for &quot;Dict[bytes, Sequence[bytes]]&quot;; expected type &quot;bytes&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately it&#x27;d be a pain to annotate our application code to mark every use of &lt;code&gt;IResponse.headers&lt;&#x2F;code&gt; as a &lt;code&gt;Headers&lt;&#x2F;code&gt; object. We&#x27;ll see a better way to do things in this &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;12&#x2F;10&#x2F;type-coverage-for-sydent-annotation&quot;&gt;the next post&lt;&#x2F;a&gt;, which discusses the nitty-gritty details of adding annotations file-by-file.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Many thanks for reading! If you&#x27;ve got any corrections, comments or queries, I&#x27;m available on Matrix at &lt;a href=&quot;https:&#x2F;&#x2F;matrix.to&#x2F;#&#x2F;@dmrobertson:matrix.org&quot;&gt;@dmrobertson:matrix.org&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>How the UK&#x27;s Online Safety Bill threatens Matrix</title>
    <published>2021-05-19T15:47:03+00:00</published>
    <updated>2021-05-19T14:48:44+00:00</updated>
    <author>
      <name>Denise Almeida</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2021/05/19/how-the-uk-s-online-safety-bill-threatens-matrix/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2021/05/19/how-the-uk-s-online-safety-bill-threatens-matrix/</id>
    <content type="html">&lt;p&gt;Last week the UK government published a &lt;a href=&quot;https:&#x2F;&#x2F;www.gov.uk&#x2F;government&#x2F;publications&#x2F;draft-online-safety-bill&quot;&gt;draft of the proposed Online Safety
Bill,&lt;&#x2F;a&gt;
after having initially introduced &lt;a href=&quot;https:&#x2F;&#x2F;www.gov.uk&#x2F;government&#x2F;consultations&#x2F;online-harms-white-paper&#x2F;public-feedback&#x2F;online-harms-white-paper-initial-consultation-response&quot;&gt;formal proposals for said bill in early
2020&lt;&#x2F;a&gt;.
With this post we aim to shed some light on its potential impacts and explain
why we think that this bill - despite having great intentions - may actually
be setting a dangerous precedent when it comes to our rights to privacy,
freedom of expression and self determination.&lt;&#x2F;p&gt;
&lt;p&gt;The proposed bill aims to provide a legal framework to address illegal and
harmful content online. This focus on “not illegal, but harmful” content is at
the centre of our concerns - it puts responsibility on organisations
themselves to arbitrarily decide what might be harmful, without any legal
backing. The bill itself does not actually provide a definition of harmful,
instead relying on service providers to assess and decide on this. This
requirement to identify what is “likely to be harmful” applies to all users,
children and adults. Our question here is - would you trust a service provider
to decide what might be harmful to you and your children, with zero input from
you as a user?&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, the bill incentivises the use of privacy-invasive age
verification processes which come with their own set of problems. This
complete disregard of people’s right to privacy is a reflection of the
privileged perspectives of those in charge of the drafting of this bill, which
fails to acknowledge how &lt;em&gt;actually&lt;&#x2F;em&gt; harmful it would be for certain groups of
the population to have their real life identity associated with their online
identity.&lt;&#x2F;p&gt;
&lt;p&gt;Our view of the world, and of the internet, is largely different from the one
presented by this bill. Now, this categorically does not mean we don’t care
about online safety (it is quite literally our bread and butter) - we just
fundamentally disagree with the approach taken.&lt;&#x2F;p&gt;
&lt;p&gt;Whilst we sympathise with the government’s desire to show action in this space
and to do something about children’s safety (everyone’s safety really), we
cannot possibly agree with the methods.&lt;&#x2F;p&gt;
&lt;p&gt;Back in October of 2020 we presented &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2020&#x2F;10&#x2F;19&#x2F;combating-abuse-in-matrix-without-backdoors&quot;&gt;our proposed approach to online safety&lt;&#x2F;a&gt; -
ironically also in response to a government proposal, albeit about encryption
backdoors. In it, we briefly discussed the dangers of absolute determinations
of morality from a single cultural perspective:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2020&#x2F;10&#x2F;19&#x2F;combating-abuse-in-matrix-without-backdoors&quot;&gt;As uncomfortable as it may be, one man’s terrorist is another man’s freedom fighter, and different jurisdictions have different laws - and it’s not up to the Matrix.org Foundation to play God and adjudicate.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;We now find ourselves reading a piece of legislation that essentially demands
these determinations from tech companies. The beauty of the human experience
lies with its diversity and when we force technology companies to make calls
about what is right or wrong - or what is “likely to have adverse
psychological or physical impacts” on children - we end up in a dangerous
place of centralising and regulating relative morals. Worst of all, when the
consequence of getting it wrong is criminal liability for senior managers what
do we think will happen?&lt;&#x2F;p&gt;
&lt;p&gt;Regardless of how omnipresent it is in our daily lives, technology is still
not a solution for human problems. Forcing organisations to be judge and jury
of human morals for the sake of “free speech” will, ironically, have severe
consequences on free speech, as risk profiles will change for fear of
liability.&lt;&#x2F;p&gt;
&lt;p&gt;Forcing a “duty of care” responsibility on organisations which operate online
will not only drown small and medium sized companies in administrative tasks
and costs, it will further accentuate the existing monopolies by Big Tech.
Plainly, Big Tech can afford the regulatory burden - small start-ups can’t.
Future creators will have their wings clipped from the offset and we might
just miss out on new ideas and projects for fear of legal repercussions. This
is a threat to the technology sector, particularly those building on emerging
technologies like Matrix. In some ways, it is a threat to democracy and some
of the freedoms this bill claims to protect.&lt;&#x2F;p&gt;
&lt;p&gt;These are, quite frankly, steps towards an authoritarian dystopia. If Trust &amp;amp;
Safety managers start censoring something as natural as a nipple on the off
chance it might cause “adverse psychological impacts” on children, whose
freedom of expression are we actually protecting here?&lt;&#x2F;p&gt;
&lt;p&gt;More specifically on the issue of content moderation: the &lt;a href=&quot;https:&#x2F;&#x2F;assets.publishing.service.gov.uk&#x2F;government&#x2F;uploads&#x2F;system&#x2F;uploads&#x2F;attachment_data&#x2F;file&#x2F;985283&#x2F;Draft_Online_Safety_Bill_-_Impact_Assessment_Web_Accessible.pdf&quot;&gt;impact assessment
provided by the government alongside this
bill&lt;&#x2F;a&gt;
predicts that the additional costs for companies directly related to the bill
will be in the billions, over the course of 10 years. The cost for the
government? £400k, in every proposed policy option. Our question is - why are
these responsibilities being placed on tech companies, when evidently this is
a societal problem?&lt;&#x2F;p&gt;
&lt;p&gt;We are not saying it is up to the government to single-handedly end the
existence of Child Sexual Abuse and Exploitation (CSAE) or extremist content
online. What we are saying is that it takes more than content filtering, risk
assessments and (faulty) age verification processes for it to end. More
funding for tech literacy organisations and schools, to give children (and
parents) the tools to stay safe is the first thing that comes to mind. Further
investment in law enforcement cyber units and the judicial system, improving
tech companies’ routes for abuse reporting and allowing the actual judges to
do the judging seems pretty sensible too. What is absolutely egregious is the
degradation of the digital rights of the majority, due to the wrongdoings of a
few.&lt;&#x2F;p&gt;
&lt;p&gt;Our goal with this post is not to be dramatic or alarmist. However, we want to
add our voices to the countless &lt;a href=&quot;https:&#x2F;&#x2F;www.openrightsgroup.org&#x2F;blog&#x2F;online-abuse-why-management-liability-isnt-the-answer&#x2F;&quot;&gt;digital rights
campaigners&lt;&#x2F;a&gt;,
individuals and organisations that have been raising the alarm since the early
days of this bill. Just like with coercive control and abuse, the degradation
of our rights does not happen all at once. It is a slippery slope that starts
with something as (seemingly) innocuous as &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;matthew_d_green&#x2F;status&#x2F;1392823038920564736&quot;&gt;mandatory content scanning for
CSAE content and ends with authoritarian surveillance
infrastructure&lt;&#x2F;a&gt;.
It is our duty to put a stop to this before it even begins.&lt;&#x2F;p&gt;
&lt;small style=&quot;display: block; text-align: right&quot;&gt;
Twitter card image credit from &lt;a href=&quot;https:&#x2F;&#x2F;film-grab.com&#x2F;2010&#x2F;10&#x2F;04&#x2F;brazil&#x2F;#bwg644&#x2F;39614&quot;&gt;Brazil&lt;&#x2F;a&gt;, which feels all too familiar right now.
&lt;&#x2F;small&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>The Matrix Space Beta!</title>
    <published>2021-05-17T17:50:17+00:00</published>
    <updated>2021-05-17T17:35:09+00:00</updated>
    <author>
      <name>Matthew Hodgson</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2021/05/17/the-matrix-space-beta/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2021/05/17/the-matrix-space-beta/</id>
    <content type="html">&lt;p&gt;Hi all,&lt;&#x2F;p&gt;
&lt;p&gt;As many know, over the years we&#x27;ve experimented with how to let users locate
and curate sets of users and rooms in Matrix. &lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@RiotChat&#x2F;communities-aka-groups-are-here-announcing-riot-web-0-13-riot-ios-0-6-and-riot-android-0-7-4-933cb193a28e&quot;&gt;Back in Nov
2017&lt;&#x2F;a&gt;
we added &#x27;groups&#x27; (aka &#x27;communities&#x27;) as a custom mechanism for this -
introducing identifiers beginning with a + symbol to represent sets of rooms
and users, like &lt;a href=&quot;https:&#x2F;&#x2F;matrix.to&#x2F;#&#x2F;+matrix:matrix.org&quot;&gt;+matrix:matrix.org&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;However, it rapidly became obvious that Communities had some major
shortcomings.  They ended up being an extensive and entirely new API surface
(designed around letting you dynamically bridge the membership of a group
through to a single source of truth like LDAP) - while in practice groups
have enormous overlap with rooms: managing membership, inviting by email,
access control, power levels, names, topics, avatars, etc.  Meanwhile the
custom groups API re-invented the wheel for things like pushing updates
to the client (causing a whole suite of
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;element-web&#x2F;issues&#x2F;5235&quot;&gt;problems&lt;&#x2F;a&gt;).  So clients
and servers alike ended up reimplementing large chunks of similar
functionality for both rooms and groups.&lt;&#x2F;p&gt;
&lt;p&gt;And so almost before Communities were born, we started thinking about whether
it would make more sense to model them as a special type of room, rather than
being their own custom primitive.
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;issues&#x2F;1215&quot;&gt;MSC1215&lt;&#x2F;a&gt; had the first
thoughts on this in 2017, and then a formal proposal emerged at
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;1772&quot;&gt;MSC1772&lt;&#x2F;a&gt; in Jan 2019. We
started working on this in earnest at the end of 2020, and christened the new
way of handling groups of rooms and users as... Spaces!&lt;&#x2F;p&gt;
&lt;p&gt;Spaces work as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;You can designate specific rooms as &#x27;spaces&#x27;, which contain other rooms.&lt;&#x2F;li&gt;
&lt;li&gt;You can have a nested hierarchy of spaces.&lt;&#x2F;li&gt;
&lt;li&gt;You can rapidly navigate around that hierarchy using the new &#x27;space summary&#x27;
(aka space-nav) API - &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;blob&#x2F;kegan&#x2F;spaces-summary&#x2F;proposals&#x2F;2946-spaces-summary.md&quot;&gt;MSC2946&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Spaces can be shared with other people publicly, or invite-only, or private
for your own curation purposes.&lt;&#x2F;li&gt;
&lt;li&gt;Rooms can appear in multiple places in the hierarchy.&lt;&#x2F;li&gt;
&lt;li&gt;You can have &#x27;secret&#x27; spaces where you group your own personal rooms and
spaces into an existing hierarchy.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Today, we&#x27;re ridiculously excited to be launching Space support as a beta in
matrix-react-sdk and matrix-android-sdk2 (and thus Element Web&#x2F;Desktop and
Element Android) and Synapse
&lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2021&#x2F;05&#x2F;17&#x2F;synapse-1-34-0-released&quot;&gt;1.34.0&lt;&#x2F;a&gt; - so head
over to your nearest Element, make sure it&#x27;s connected to the latest Synapse
(and that Synapse has Spaces enabled in its config) and find some Space to
explore! &lt;a href=&quot;https:&#x2F;&#x2F;matrix.to&#x2F;#&#x2F;#community:matrix.org&quot;&gt;#community:matrix.org&lt;&#x2F;a&gt;
might be a good start :)&lt;&#x2F;p&gt;
&lt;p&gt;The beta today gives us the bare essentials: and we haven&#x27;t yet finished
space-based access controls such as setting powerlevels in rooms based on
space membership
(&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;blob&#x2F;matthew&#x2F;msc2962&#x2F;proposals&#x2F;2962-spaces-access-control.md&quot;&gt;MSC2962&lt;&#x2F;a&gt;)
or limiting who can join a room based on their space membership
(&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;blob&#x2F;clokep&#x2F;restricted-rooms&#x2F;proposals&#x2F;3083-restricted-rooms.md&quot;&gt;MSC3083&lt;&#x2F;a&gt;) -
but these will be coming asap.  We also need to figure out how to implement
Flair on top of Spaces rather than Communities.&lt;&#x2F;p&gt;
&lt;p&gt;This is also a bit of a turning point in Matrix&#x27;s architecture: we are now
using rooms more and more as a generic way of modelling new features in
Matrix.  For instance, rooms could be used as a structured way of storing
files (&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;3089&quot;&gt;MSC3089&lt;&#x2F;a&gt;);
Reputation data
(&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2313&quot;&gt;MSC2313&lt;&#x2F;a&gt;) is stored in
rooms; Threads can be stored in rooms
(&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2836&quot;&gt;MSC2836&lt;&#x2F;a&gt;); Extensible
Profiles are proposed as rooms too
(&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;1769&quot;&gt;MSC1769&lt;&#x2F;a&gt;).  As such,
this pushes us towards ensuring rooms are as lightweight as possible in Matrix -
and that things like sync and changing profile scale independently of the
number of rooms you&#x27;re in.  Spaces effectively gives us a way of creating a
global decentralised filesystem hierarchy on top of Matrix - grouping the
existing rooms of all flavours into an epic multiplayer tree of realtime data.
It&#x27;s like USENET had a baby with the Web!&lt;&#x2F;p&gt;
&lt;p&gt;For lots more info from the Element perspective, head over to the &lt;a href=&quot;https:&#x2F;&#x2F;element.io&#x2F;blog&#x2F;p&#x2F;4ff44807-fe9a-4363-8521-9eab7efd4365&#x2F;&quot;&gt;Element
blog&lt;&#x2F;a&gt;.
Finally, the point of the beta is to gather feedback and fix bugs - so please
go wild in Element reporting your first impressions and help us make Spaces as
awesome as they deserve to be!&lt;&#x2F;p&gt;
&lt;p&gt;Thanks for flying Matrix into Space;&lt;&#x2F;p&gt;
&lt;p&gt;Matthew &amp;amp; the whole Spaces (and Matrix) team.&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>Introducing the Pinecone overlay network</title>
    <published>2021-05-06T00:00:00+00:00</published>
    <updated>2021-05-06T00:00:00+00:00</updated>
    <author>
      <name>Neil Alexander</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2021/05/06/introducing-the-pinecone-overlay-network/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2021/05/06/introducing-the-pinecone-overlay-network/</id>
    <content type="html">&lt;p&gt;Since the end of 2019, we have spent quite a bit of time thinking about and exploring different technologies whilst building various demos for P2P Matrix.  Our mission for P2P Matrix is to evolve Matrix into a hybrid between today&#x27;s server-oriented network and a pure P2P network - empowering users to have &lt;strong&gt;total&lt;&#x2F;strong&gt; autonomy and privacy over their data if they want (by storing it in P2P Matrix, by embedding their server into their Matrix client), while also letting users store their data in serverside nodes if they so desire.&lt;&#x2F;p&gt;
&lt;p&gt;The goal is to protect metadata much better (as users no longer have to depend on a server run by someone else to communicate), as well as drive new features such as account portability, multi-homed accounts, low-bandwidth Matrix and smarter federation transports - and provide support for internet-less mesh communication via Matrix which can also interoperate with the wider network.  You can read more about it in our &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2020&#x2F;06&#x2F;02&#x2F;introducing-p-2-p-matrix&#x2F;&quot;&gt;Introducing P2P Matrix&lt;&#x2F;a&gt; blog post from last summer, or watch our &lt;a href=&quot;https:&#x2F;&#x2F;fosdem.org&#x2F;2021&#x2F;schedule&#x2F;event&#x2F;matrix_pinecones&#x2F;&quot;&gt;FOSDEM 2021 talk&lt;&#x2F;a&gt; where we previewed Pinecone.  It&#x27;s important to note that this has been a small but important long-term project for Matrix, and has been progressing entirely outside our business-as-usual work of improving the core protocol and reference implementations.&lt;&#x2F;p&gt;
&lt;p&gt;As the project has progressed, we&#x27;ve built a variety of prototypes using existing libraries (&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;libp2p&#x2F;go-libp2p&quot;&gt;go-libp2p&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;libp2p&#x2F;js-libp2p&quot;&gt;js-libp2p&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yggdrasil-network&#x2F;yggdrasil-go&quot;&gt;Yggdrasil&lt;&#x2F;a&gt;), demonstrating what an early P2P Matrix might feel like if it were running on a mobile device, in the web browser and so on using such an overlay network. Each of these demos has taught us something new, and so in October 2020 we decided to take this knowledge to build an experimental new overlay network of our own.&lt;&#x2F;p&gt;
&lt;p&gt;Pinecone is designed to provide end-to-end encrypted communications between devices, regardless of how they are connected to one another, in a lightweight and self-arranging fashion. The routing protocol is a hybrid, taking inspiration from &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yggdrasil-network&#x2F;yggdrasil-go&quot;&gt;Yggdrasil&lt;&#x2F;a&gt; by building a global spanning tree, but rather than forwarding all traffic using the spanning tree topology, we use it as a bootstrap routing mechanism for a line&#x2F;snake topology, ordered by their ed25519 public keys, which we have affectionately named SNEK (Sequentially Networked Edwards Key) routing.&lt;&#x2F;p&gt;
&lt;p&gt;Nodes seek out their closest keyspace neighbours on the network and paths are built between these pairs of nodes, similar to how a Chord DHT functions, populating the routing tables of intermediate nodes in the process. These paths are then used to forward traffic without having to perform up-front searches, allowing for very fast connection setups between overlay nodes. These paths are resilient to network topology changes and handle node mobility considerably better than any other name-independent routing scheme that we have seen — early results are very promising so far. We have also been experimenting with a combination of the μTP (Micro Transport Protocol) and TLS to provide stateful connection setup, congestion control and end-to-end encryption for all federation traffic carried over the Pinecone network.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;img&#x2F;2021-05-06-pineconesim.png&quot; alt=&quot;Pinecone simulator showing line&#x2F;snake logical network topology&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If Pinecone works out, our intention is to collaborate with the libp2p and IPFS team to incorporate Pinecone routing into libp2p (if they&#x27;ll have us!) while incorporating their gossipsub routing to improve Matrix federation... and get the best of both worlds :)&lt;&#x2F;p&gt;
&lt;p&gt;Today we&#x27;re releasing the source code for our current early implementation of Pinecone — you can &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;pinecone&quot;&gt;get it from GitHub&lt;&#x2F;a&gt; right now! It&#x27;s very experimental still and not very well optimised yet, but it is the foundation of our latest mobile P2P Matrix demos, which support P2P Matrix over both &lt;strong&gt;Bluetooth Low Energy&lt;&#x2F;strong&gt; mesh networks, &lt;strong&gt;multicast DNS&lt;&#x2F;strong&gt; discovery within a LAN, and&#x2F;or by routing through &lt;strong&gt;static Pinecone peers&lt;&#x2F;strong&gt; on the Internet:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Android: &lt;a href=&quot;https:&#x2F;&#x2F;appdistribution.firebase.dev&#x2F;i&#x2F;394600067ea8ba37&quot;&gt;https:&#x2F;&#x2F;appdistribution.firebase.dev&#x2F;i&#x2F;394600067ea8ba37&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;iOS: &lt;a href=&quot;https:&#x2F;&#x2F;testflight.apple.com&#x2F;join&#x2F;Tgh2MEk6&quot;&gt;https:&#x2F;&#x2F;testflight.apple.com&#x2F;join&#x2F;Tgh2MEk6&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Building a routing overlay is only the first step in the journey towards P2P Matrix. We will also be looking closely in the coming months at improving the Matrix federation protocol to work well in mixed-connectivity scenarios (rather than the full mesh approach used today) as well as decentralised identities, hybrid deployments with existing homeservers and getting Dendrite (the Matrix homeserver which is embedded into the current P2P demos) more stable and feature-complete.&lt;&#x2F;p&gt;
&lt;p&gt;The long-term plan could look something like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;img&#x2F;2021-05-06-pinecone.png&quot; alt=&quot;Diagram showing possible P2P Matrix stack&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Most discussion around P2P Matrix takes place in &lt;a href=&quot;http:&#x2F;&#x2F;matrix.to&#x2F;#&#x2F;#p2p:matrix.org&quot;&gt;#p2p:matrix.org&lt;&#x2F;a&gt;, so if you are interested in what&#x27;s going on, please join us there!&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>Privacy improvements in Synapse 1.4 and Riot 1.4</title>
    <published>2019-09-27T00:00:00+00:00</published>
    <updated>2019-09-27T00:00:00+00:00</updated>
    <author>
      <name>Matthew Hodgson</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2019/09/27/privacy-improvements-in-synapse-1-4-and-riot-1-4/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2019/09/27/privacy-improvements-in-synapse-1-4-and-riot-1-4/</id>
    <content type="html">&lt;p&gt;Hi all,&lt;&#x2F;p&gt;
&lt;p&gt;Back in June we wrote about our &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2019&#x2F;06&#x2F;30&#x2F;tightening-up-privacy-in-matrix&quot;&gt;plans to tighten up data
privacy&lt;&#x2F;a&gt;
in Matrix after some areas for improvement were brought to our attention.  To
quickly recap: the primary concern was that the default config for Riot
specifies identity servers and integration managers run by New Vector (the
company which the original Matrix team set up to build Riot and fund Matrix
dev) - and so folks using a standalone homeserver may end up using external
services without realising it.  There were some other legitimate issues raised
too (e.g. contact information should be obfuscated when checking if your
contacts are on Matrix; Riot defaulted to using Google for STUN (firewall
detection) if no TURN server had been set up on their server; Synapse defaults
to using matrix.org as a key notary server).&lt;&#x2F;p&gt;
&lt;p&gt;We’ve been working away at this fairly solidly over the last few months.  Some
of the simpler items shipped quickly (e.g. Riot&#x2F;Web had a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-react-sdk&#x2F;pull&#x2F;3115&quot;&gt;stupid
bug&lt;&#x2F;a&gt; where it kept
incorrectly loading the integration manager; Riot&#x2F;Android &lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=20181515&quot;&gt;wasn’t clear
enough&lt;&#x2F;a&gt; about when contact
discovery was happening; Riot&#x2F;Web &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10216&quot;&gt;wasn’t clear
enough&lt;&#x2F;a&gt; about the fact
device names are publicly visible; etc) - but other bits have turned out to be
incredibly time-consuming to get right.&lt;&#x2F;p&gt;
&lt;p&gt;However, we’re in the process today of releasing Synapse 1.4.0 and Riot&#x2F;Web
1.4.0 (it’s coincidence the version numbers have lined up!) which resolve the
majority of the remaining issues.  The main changes are as follows:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Riot no longer automatically uses identity servers by default&lt;&#x2F;strong&gt;.&lt;br &#x2F;&gt;
Identity servers are only useful when inviting users by email address, or when
discovering whether your contacts are on Matrix.  Therefore, we now wait until
the user tries to perform one of these operations before explaining that they
need an identity server to do so, and we prompt them to select one if they
want to proceed. This makes it abundantly clear that the user is connecting to
an independent service, and why.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Integration Managers and identity servers now have the ability to force
users to accept terms of use before using them&lt;&#x2F;strong&gt;.&lt;br &#x2F;&gt;
This means they can explicitly spell out the data privacy &amp;amp; usage policy of
the server as required by GDPR, and it should now be impossible for a user
to use these services without realising it.  This was particularly fun in
the case of identity servers, which previously had no concept of users and
so couldn’t track whether users had agreed to their terms &amp;amp; conditions or
not… and because homeservers sometimes talk to the identity server on behalf
of users rather than the user talking direct, the privacy policy flow gets
even hairier.  But it’s solved now, and a nice side-effect of this is that
users can now explicitly select their Integration Manager in Riot, in case
they want to use &lt;a href=&quot;https:&#x2F;&#x2F;dimension.t2bot.io&quot;&gt;Dimension&lt;&#x2F;a&gt; or similar rather
than the default provided by &lt;a href=&quot;https:&#x2F;&#x2F;modular.im&quot;&gt;Modular&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Synapse no longer uses identity servers for verifying registrations or
verifying password reset.&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Originally, Synapse made use of the fact that the Identity Service contains
email&#x2F;msisdn verification logic to handle identity verification in general
on behalf of the homeserver. However, in retrospect this was a mistake: why
should the entity running your identity server have the right to verify
password resets or registration details on your homeserver?  So, we have
moved this logic into Synapse.  &lt;strong&gt;This means Synapse 1.4.0 requires new
configuration for email&#x2F;msisdn verification to work - please see the upgrade
notes for full details.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sydent now supports discovering contacts based on hashed identifiers.&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;blob&#x2F;hs&#x2F;hash-identity&#x2F;proposals&#x2F;2134-identity-hash-lookup.md&quot;&gt;MSC2134&lt;&#x2F;a&gt;
specifies entirely new IS APIs for discovering contacts using a hash of
their identifier rather than directly exposing the raw identifiers being
searched for.  This is implemented in
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2652&quot;&gt;Riot&#x2F;iOS&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3257&quot;&gt;Riot&#x2F;Android&lt;&#x2F;a&gt; and
should be in the next major release;
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10556&quot;&gt;Riot&#x2F;Web&lt;&#x2F;a&gt; 1.4.0 has it
already.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Synapse now &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6090&#x2F;files&quot;&gt;warns in its
logs&lt;&#x2F;a&gt; if you are
using matrix.org as a default trusted key server, in case you wish to use a
different server to help discover other servers’ keys.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Synapse now &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;1287&quot;&gt;garbage collects redacted
messages&lt;&#x2F;a&gt; after N days (7
days by default).  (It doesn’t yet garbage collect attachments referenced
from redacted messages; we’re still working on that).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Synapse now &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6098&#x2F;files&quot;&gt;deletes account access
data&lt;&#x2F;a&gt; (IP addresses
and User Agent) after N days (28 days by default) of a device being deleted.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Riot warns before falling back to using STUN (and defaults to
turn.matrix.org rather than stun.google.com) for firewall discovery (STUN)
when placing VoIP calls, and makes it clear that this is an emergency
fallback for misconfigured servers which are missing TURN support.  (We
originally deleted the fallback entirely, but this broke things for too many
people, so we’ve kept it but warn instead).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;All of this is implemented in Riot&#x2F;Web 1.4.0 and Synapse 1.4.0.  Riot&#x2F;Web
1.4.0 shipped today (Fri Sept 27th) and we have a release candidate
for Synapse 1.4 (1.4.0rc1) today which fully ship on Monday.&lt;&#x2F;p&gt;
&lt;p&gt;For full details please go check out the &lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@RiotChat&#x2F;new-privacy-controls-for-riot-dc3661888563&quot;&gt;Riot 1.4.0&lt;&#x2F;a&gt;
and &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;blog&#x2F;2019&#x2F;10&#x2F;03&#x2F;synapse-1-4-0-released&quot;&gt;Synapse 1.4.0&lt;&#x2F;a&gt; blog posts.&lt;&#x2F;p&gt;
&lt;p&gt;Riot&#x2F;Mobile is following fast behind - most of the above has been implemented
and everything should land in the next release.  RiotX&#x2F;Android doesn’t really
have any changes to make given it hadn’t yet implemented Identity Service or
Integration Manager APIs.&lt;&#x2F;p&gt;
&lt;p&gt;This has involved a surprisingly large amount of spec work; no fewer than 9
new Matrix Spec Changes (MSC) have been required as part of the project.  In
particular, this results in a massive update to the Identity Service API,
which will be released very shortly with the new MSCs.  You can see the
upcoming changes on the &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;docs&#x2F;spec&#x2F;identity_service&#x2F;unstable&quot;&gt;unstable
branch&lt;&#x2F;a&gt; and compare
with the &lt;a href=&quot;https:&#x2F;&#x2F;matrix.org&#x2F;docs&#x2F;spec&#x2F;identity_service&#x2F;r0.2.1&quot;&gt;previous 0.2.1 stable
release&lt;&#x2F;a&gt;, as well as
checking the detailed MSCs as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;1961&quot;&gt;MSC1961: Integration manager authentication APIs&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2078&quot;&gt;MSC2078: Sending Third-Party Request Tokens via the Homeserver&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2134&quot;&gt;MSC2134: Identity Hash Lookups&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2140&quot;&gt;MSC2140: Terms of Service for ISes and IMs&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2229&quot;&gt;MSC2229: Allowing 3PID Owners to Rebind&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2230&quot;&gt;MSC2230: Store Identity Server in Account Data&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2263&quot;&gt;MSC2263: Give homeservers the ability to handle their own 3PID registrations&#x2F;password resets&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2264&quot;&gt;MSC2264: Add an unstable feature flag to MSC2140 for clients to detect support&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2290&quot;&gt;MSC2290: Separate Endpoints for Threepid Binding&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This said, there is still some work remaining for us to do here.  The main
things which haven’t made it into this release are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Preferring to get server keys from the source server rather than the notary server by default (&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6110&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6110&lt;&#x2F;a&gt;). This almost made it in, but we need to test it more first - until then, your specified notary server will see roughly what servers your servers are trying to talk to.  In future this will be mitigated properly by &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;issues&#x2F;1228&quot;&gt;MSC1228 (removing mxids from events)&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Configurable data retention periods for rooms.  We are tantalisingly close with this - &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5815&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5815&lt;&#x2F;a&gt; is an implementation that the French Govt deployment is using; we need to port it into mainline Synapse.&lt;&#x2F;li&gt;
&lt;li&gt;Authenticating access to the media repository - for now, we still rely on media IDs being almost impossible to guess to protect the data rather than authenticating the user.&lt;&#x2F;li&gt;
&lt;li&gt;Deleting items from the media repository - we still need to hook up deletion APIs.&lt;&#x2F;li&gt;
&lt;li&gt;Garbage collecting forgotten rooms.  If everyone leaves &amp;amp; forgets a room, we should delete it from the DB.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;issues&#x2F;1280&quot;&gt;Communicating erasure requests over federation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We’ll continue to work on these as part of our ongoing maintenance backlog.&lt;&#x2F;p&gt;
&lt;p&gt;Separately to the data privacy concerns, we’ve had a &lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=20515069&quot;&gt;separate wave of
feedback&lt;&#x2F;a&gt; regarding how we
handle GDPR Data Subject Access Requests (DSARs). Particularly: whether DSAR
responses should contain solely the info your have directly keyed by the
requesting Matrix ID - or if we should provide all the data “visible” to that
ID (i.e. the history of the conversations they’ve been part of).  We went and
got professional legal advice on this one, and the conclusion is that we
should keep our responses to DSARs as tightly scoped as possible. We &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;policies&#x2F;pull&#x2F;7&#x2F;files?short_path=09dc019#diff-09dc019b94b6efb90fa9f6e5c836f310&quot;&gt;updated
Matrix.org’s privacy
policy&lt;&#x2F;a&gt;
and DSAR tools to reflect the new legal input.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, it’s really worth calling out the amount of effort that went into
this project. Huge huge thanks to everyone involved (given it’s cut across
pretty much every project &amp;amp; subteam we have working on the core of Matrix) who
have soldiered through the backlog.  We’ve been tracking progress using our
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;feature-dashboard&quot;&gt;feature-dashboard&lt;&#x2F;a&gt; tool which
summarises Github issues based on labels &amp;amp; issue lifecycle, and for better or
worse it’s ended up being the biggest project board we’ve ever had.  You can
see the live data
&lt;a href=&quot;https:&#x2F;&#x2F;vector-im.github.io&#x2F;feature-dashboard&#x2F;#&#x2F;plan?label=privacy-sprint&amp;amp;repo=vector-im&#x2F;riot-web&amp;amp;repo=vector-im&#x2F;riot-ios&amp;amp;repo=vector-im&#x2F;riot-android&amp;amp;repo=vector-im&#x2F;riotX-android&amp;amp;repo=matrix-org&#x2F;matrix-doc&amp;amp;repo=matrix-org&#x2F;sydent&amp;amp;repo=matrix-org&#x2F;synapse&quot;&gt;here&lt;&#x2F;a&gt;
(warning, it takes tens of seconds to spider Github to gather the data) - or,
for posterity and ease of reference, I’ve included the current issue list
below.  The issues which are completed have “done” after them; the ones still
in progress say “in progress”, and ones which haven’t started yet have
nothing. We split the project into 3 phases - phases 1 and 2 represent the
items needed to fully solve the privacy concerns, phase 3 is right now a mix
of &quot;nice to have&quot; polish and some more speculative items.  At this point we’ve
effectively finished phase 1 on Synapse &amp;amp; Riot&#x2F;Web, and Riot&#x2F;Mobile is
following close behind.  We&#x27;re continuing to work on phase 2, and we’ll work
through phase 3 (where appropriate) as part of our general maintenance
backlog.&lt;&#x2F;p&gt;
&lt;p&gt;I hope this gives suitable visibility on how we’re considering privacy; after
all, Matrix is useless as an open communication protocol if the openness comes
at the expense of user privacy.  We’ll give another update once the remaining
straggling issues are closed out; and meanwhile, now the bulk of the privacy
work is out of the way on Riot&#x2F;Web, we can &lt;strong&gt;finally&lt;&#x2F;strong&gt; get back to
implementing the UI E2E cross-signing verification and improving first time
user experience.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks for your patience and understanding while we’ve sorted this stuff out;
and thanks once again for flying Matrix :)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;In the absence of comments on the current blog, please feel free to discuss
over at &lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=21091908&quot;&gt;HN&lt;&#x2F;a&gt;, or alternatively come ask stuff in
our AMA over at
&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;privacy&#x2F;comments&#x2F;da219t&#x2F;im_project_lead_for_matrixorg_the_open_protocol&#x2F;&quot;&gt;&#x2F;r&#x2F;privacy&lt;&#x2F;a&gt;
(starting ~5pm GMT+1 (UK) on Friday Sept 27th).&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-privacy-project-dashboard-of-doom&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-privacy-project-dashboard-of-doom&quot; aria-label=&quot;Anchor link for: the-privacy-project-dashboard-of-doom&quot;&gt;🔗&lt;&#x2F;a&gt;The Privacy Project Dashboard Of Doom&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;phase:1
&lt;ul&gt;
&lt;li&gt;vector-im&#x2F;riot-web
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;5846&quot;&gt;5846 Riot duplicates calls to Scalar&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;5921&quot;&gt;5921 Ability to disable all identity server functionality via the config file&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;6802&quot;&gt;6802 riot shouldn&#x27;t try to load integrations from an integration manager unless the user has accepted that manager&#x27;s privacy policies&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10088&quot;&gt;10088 Prompt to accept integration manager polices on use&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10090&quot;&gt;10090 Make sure there are no ugly edge cases running Riot without an integrations manager&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10091&quot;&gt;10091 Decouple setting an email for password reset from publishing your threepid to the identity server and support choice of identity server (on registration)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10092&quot;&gt;10092 Prompt to accept Identity Server policies on registration&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10093&quot;&gt;10093 Prompt to accept identity server policies before inviting them to a room&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10094&quot;&gt;10094 Store identity server in Account Data and support choosing identity server integration in User Settings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10159&quot;&gt;10159 Enable toggling a threepid&#x27;s association with the current IS in User Settings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10173&quot;&gt;10173 VoIP: Stop falling back to Google for STUN&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10216&quot;&gt;10216 We should make it clear in the UI that device names are publicly readable&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10386&quot;&gt;10386 Terms modal prompt should appear without a flash of the integration manager portal first&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10408&quot;&gt;10408 Identity server v2 API authentication&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10423&quot;&gt;10423 Deploy a develop environment for t&#x27;s and c&#x27;s flows for IM and IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10424&quot;&gt;10424 Remove the bind true flag from 3PID calls on registration&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10425&quot;&gt;10425 Ability to disconnect from the identity server by pressing buttons in user settings.&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10452&quot;&gt;10452 Test IS v2 access tokens for validity&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10497&quot;&gt;10497 Integration manager terms hides terms that need signing&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10510&quot;&gt;10510 Remove the bind true flag from 3PID adds in settings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10519&quot;&gt;10519 Update discovery and account 3PID sections when either changes&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10522&quot;&gt;10522 Handle terms agreement in the Discovery section of settings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10525&quot;&gt;10525 IS interactions proxied through the HS also need terms agreement&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10528&quot;&gt;10528 don&#x27;t try &amp;amp; show threepids in discovery section if we don&#x27;t have an ID server&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10539&quot;&gt;10539 Inline terms agreement on change IS and IM&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10540&quot;&gt;10540 When using Riot without an IS, identity requests are sent to server hosting Riot&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10546&quot;&gt;10546 Prompt for fallback VOIP should only happen when the user tries to make a call&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10550&quot;&gt;10550 warn when disconnecting ID server if there are any current bindings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10552&quot;&gt;10552 Allow email registration, password reset &amp;amp; adding 3pids when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10553&quot;&gt;10553 Remove the ability to set an IS at login&#x2F;registration&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10556&quot;&gt;10556 Use the hashed v2 lookup API for 3PIDs&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10561&quot;&gt;10561 Scalar should serve a .well-known file&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10566&quot;&gt;10566 Use nicer APIs for toggling a 3PID&#x27;s shared status&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10571&quot;&gt;10571 Allow email registration when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10572&quot;&gt;10572 Allow password reset when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10573&quot;&gt;10573 Allow adding 3pids when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10574&quot;&gt;10574 Placeholder issue for MSCs that should land prior to the privacy release&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10593&quot;&gt;10593 Placeholder issue for privacy migration path&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10597&quot;&gt;10597 Ensure IS in account data is read &#x2F; written as specced&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10599&quot;&gt;10599 Send IS for adding MSISDNs only when required by HS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10603&quot;&gt;10603 Getting a terms prompt when inviting an email address clears the address picker&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10619&quot;&gt;10619 Handle the case of no IS in features that require IS to lookup&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10620&quot;&gt;10620 Change auth flows so that you default to no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10634&quot;&gt;10634 Changing to vector.im IS in Settings fails because &#x2F;terms 404s&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10635&quot;&gt;10635 Inline terms agreement in Discovery should still show change and do not use&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10636&quot;&gt;10636 The UX is a little confusing if you haven&#x27;t accepted the terms of the default identity server.&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10637&quot;&gt;10637 Unable to add email address to HS account without IS set&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10660&quot;&gt;10660 Sydent implementation: Unauthed v1, clone all endpoints, auth v2&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10666&quot;&gt;10666 In login&#x2F;register, riot freezes if you go to Advanced, remove the IS url and click next&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10669&quot;&gt;10669 Checking email invite account is unclear when no IS set&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10674&quot;&gt;10674 Email help text on registration should be updated without binding&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10677&quot;&gt;10677 Change text about other users being able to invite you by email on registration page&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10744&quot;&gt;10744 Only set terms URLs in the account when they change&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10749&quot;&gt;10749 Changing from one IS to another does not trigger bound 3PID warning&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10750&quot;&gt;10750 Bound 3PIDs warning should better explain what&#x27;s being left behind&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10754&quot;&gt;10754 Lowercase emails during IS lookup calls&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10755&quot;&gt;10755 Terms account data is meant to be additive, but currently sets only new URLs&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10756&quot;&gt;10756 After changing IS to termstest.matrix.org the text field isn&#x27;t cleared and the button remains active&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10757&quot;&gt;10757 After changing IS back to vector.im the text field isn&#x27;t cleared and the button remains active&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10758&quot;&gt;10758 Revoke may be too vague for unbinding a 3PID&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10779&quot;&gt;10779 When publishing a threepid to an IS, if you click &#x27;continue&#x27; before clicking the link in your email, we delete your threepid from the HS.&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10800&quot;&gt;10800 Community invite should not talk about ISes at all.&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10823&quot;&gt;10823 IS with unagreed terms will block you from adding even unshared 3PIDs to your HS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10839&quot;&gt;10839 Use the new backend APIs for adding-3pid-to-homeserver and binding-3pid-on-identity-server when they exist.&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10878&quot;&gt;10878 UX regression when trying to invite by email if no IS is configured&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10883&quot;&gt;10883 Riot should check for r0.6.0 server support alongside feature flags&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10923&quot;&gt;10923 Send validation tokens to submit_url from HS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10933&quot;&gt;10933 Do not include ID server or access token when HS supports MSC2290&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10939&quot;&gt;10939 Registration with MSISDN needs to use submit_url&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10941&quot;&gt;10941 threepid_creds for registration and password reset still include id_server&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10959&quot;&gt;10959 Remove id_server from email threepid_creds&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10604&quot;&gt;10604 QA: Re-test ALL of the identity server interactions&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10958&quot;&gt;10958 Terms of Service nitpicks&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10704&quot;&gt;10704 We treat an empty string identity server as not having one&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;vector-im&#x2F;riot-ios
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2518&quot;&gt;2518 Make sure there are no ugly edge cases running Riot without an integrations manager&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2521&quot;&gt;2521 Privacy: Improve wording on contact upload UI&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2532&quot;&gt;2532 VoIP: Stop falling back to Google for STUN&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2600&quot;&gt;2600 Prompt to accept integration manager polices on use&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2601&quot;&gt;2601 Decouple setting an email for password reset from publishing your threepid to the identity server and support choice of identity server (on registration)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2602&quot;&gt;2602 Prompt to accept identity server policies before inviting them to a room&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2603&quot;&gt;2603 Identity server v2 API authentication&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2606&quot;&gt;2606 Settings: Add a Discovery section&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2608&quot;&gt;2608 Registration: Update consents flow&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2643&quot;&gt;2643 Ability to disable all identity server functionality via the config file&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2646&quot;&gt;2646 VoIP: Fallback to matrix.org STUN server with a confirmation dialog&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2647&quot;&gt;2647 MXRestClient: Move IS API to its own&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2648&quot;&gt;2648 Remove the bind true flag from 3PID calls on registration&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2650&quot;&gt;2650 Remove the bind true flag from 3PID adds in settings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2651&quot;&gt;2651 Store identity server in Account Data and support choosing identity server integration in User Settings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2652&quot;&gt;2652 Use the hashed v2 lookup API for 3PIDs&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2653&quot;&gt;2653 Allow email registration, password reset &amp;amp; adding 3pids when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2654&quot;&gt;2654 Use nicer APIs for toggling a 3PID&#x27;s shared status&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2657&quot;&gt;2657 Allow email registration when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2658&quot;&gt;2658 Allow password reset when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2659&quot;&gt;2659 Allow adding 3pids when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2660&quot;&gt;2660 Handle terms agreement in the Discovery section of settings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2661&quot;&gt;2661 Remove the ability to set an IS at login&#x2F;registration&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2662&quot;&gt;2662 We should make it clear in the UI that device names are publicly readable&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2664&quot;&gt;2664 Placeholder issue for privacy migration path&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2665&quot;&gt;2665 Ensure IS in account data is read &#x2F; written as specced&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2672&quot;&gt;2672 Handle the case of no IS in features that require IS to lookup&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2675&quot;&gt;2675 Email help text on registration should be updated without binding&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2682&quot;&gt;2682 Send IS for adding MSISDNs only when required by HS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2686&quot;&gt;2686 Use wellknown to discover the IS of a custom HS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2696&quot;&gt;2696 Lowercase emails during IS lookup calls&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2704&quot;&gt;2704 Use &lt;code&gt;id_access_token&lt;&#x2F;code&gt; in CS API when required&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2604&quot;&gt;2604 Settings: Ability to change the identity server&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2649&quot;&gt;2649 Ability to disconnect from the identity server by pressing buttons in user settings&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2713&quot;&gt;2713 Use the new backend APIs for adding-3pid-to-homeserver and binding-3pid-on-identity-server when they exist.&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2718&quot;&gt;2718 Riot should check for r0.6.0 server support alongside feature flags&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2683&quot;&gt;2683 Checking email invite account is unclear when no IS set&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2731&quot;&gt;2731 Send validation tokens to submit_url from HS&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2732&quot;&gt;2732 Do not include ID server or access token when HS supports MSC2290&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2736&quot;&gt;2736 IS terms cannot be accepted anymore&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;vector-im&#x2F;riot-android
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3223&quot;&gt;3223 VoIP: Stop falling back to Google for STUN&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3224&quot;&gt;3224 Make sure there are no ugly edge cases running Riot without an integrations manager&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3225&quot;&gt;3225 Prompt to accept integration manager polices on use&lt;&#x2F;a&gt;(done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3226&quot;&gt;3226 Decouple setting an email for password reset from publishing your threepid to the identity server and support choice of identity server (on registration)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3227&quot;&gt;3227 Prompt to accept identity server policies before inviting them to a room&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3228&quot;&gt;3228 Identity server v2 API authentication&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3229&quot;&gt;3229 Settings: Ability to change the identity server&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3230&quot;&gt;3230 Settings: Add a Discovery section&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3231&quot;&gt;3231 Registration: Update consents flow&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3252&quot;&gt;3252 Remove the bind true flag from 3PID calls on registration&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3253&quot;&gt;3253 Ability to disconnect from the identity server by pressing buttons in user settings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3254&quot;&gt;3254 Remove the bind true flag from 3PID adds in settings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3256&quot;&gt;3256 Store identity server in Account Data and support choosing identity server integration in User Settings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3257&quot;&gt;3257 Use the hashed v2 lookup API for 3PIDs&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3258&quot;&gt;3258 Allow email registration, password reset &amp;amp; adding 3pids when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3260&quot;&gt;3260 Allow email registration when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3261&quot;&gt;3261 Allow password reset when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3262&quot;&gt;3262 Allow adding 3pids when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3263&quot;&gt;3263 Handle terms agreement in the Discovery section of settings&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3264&quot;&gt;3264 Remove the ability to set an IS at login&#x2F;registration&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3265&quot;&gt;3265 We should make it clear in the UI that device names are publicly readable&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3268&quot;&gt;3268 Placeholder issue for privacy migration path&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3269&quot;&gt;3269 Ensure IS in account data is read &#x2F; written as specced&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3277&quot;&gt;3277 Handle the case of no IS in features that require IS to lookup&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3278&quot;&gt;3278 Email help text on registration should be updated without binding&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3281&quot;&gt;3281 Send IS for adding MSISDNs only when required by HS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3283&quot;&gt;3283 Use wellknown to discover the IS of a custom HS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3289&quot;&gt;3289 Lowercase emails during IS lookup calls&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3295&quot;&gt;3295 Use &lt;code&gt;id_access_token&lt;&#x2F;code&gt; in CS API when required&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3300&quot;&gt;3300 Use the new backend APIs for adding-3pid-to-homeserver and binding-3pid-on-identity-server when they exist.&lt;&#x2F;a&gt;(done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3312&quot;&gt;3312 Riot should check for r0.6.0 server support alongside feature flags&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3316&quot;&gt;3316 Implement MSC2290&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3324&quot;&gt;3324 id_server param sent when registering an email on server that does not requires one&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3326&quot;&gt;3326 Discovery Settings &#x2F; infinite loading if terms not signed on existing IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3327&quot;&gt;3327 vector.im is seen as having no terms, but it does&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3251&quot;&gt;3251 VoIP: Fallback to matrix.org STUN server with a confirmation dialog&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3248&quot;&gt;3248 Ability to disable all identity server functionality via the config file&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3318&quot;&gt;3318 Send validation tokens to submit_url from HS&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3322&quot;&gt;3322 Do not include ID server or access token when HS supports MSC2290&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;vector-im&#x2F;riotX-android
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riotX-android&#x2F;issues&#x2F;490&quot;&gt;490 Allow email registration, password reset &amp;amp; adding 3pids when no IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riotX-android&#x2F;issues&#x2F;432&quot;&gt;432 Prompt to accept integration manager polices on use&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riotX-android&#x2F;issues&#x2F;431&quot;&gt;431 Make sure there are no ugly edge cases running Riot without an integrations manager&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riotX-android&#x2F;issues&#x2F;433&quot;&gt;433 Decouple setting an email for password reset from publishing your threepid to the identity server and support choice of identity server (on registration)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riotX-android&#x2F;issues&#x2F;434&quot;&gt;434 Prompt to accept identity server policies before inviting them to a room&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riotX-android&#x2F;issues&#x2F;435&quot;&gt;435 Identity server v2 API authentication&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riotX-android&#x2F;issues&#x2F;436&quot;&gt;436 Settings: Ability to change the identity server&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riotX-android&#x2F;issues&#x2F;438&quot;&gt;438 Settings: Add a Discovery section&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riotX-android&#x2F;issues&#x2F;439&quot;&gt;439 Registration: Update consents flow&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riotX-android&#x2F;issues&#x2F;489&quot;&gt;489 Use the hashed v2 lookup API for 3PIDs&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;matrix-org&#x2F;matrix-doc
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;1961&quot;&gt;1961 MSC1961: Integration manager authentication APIs&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2078&quot;&gt;2078 MSC2078: Sending Third-Party Request Tokens via the Homeserver&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;issues&#x2F;2130&quot;&gt;2130 Identity service should do lookups based on hashed 3PIDs, not plaintext ones.&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2134&quot;&gt;2134 MSC2134: Identity Hash Lookups&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;issues&#x2F;2139&quot;&gt;2139 Method for ISes and Integration managers to provide terms of service&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2140&quot;&gt;2140 MSC2140: Terms of Service for ISes and IMs&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2229&quot;&gt;2229 MSC2229: Allowing 3PID Owners to Rebind&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2230&quot;&gt;2230 MSC2230: Store Identity Server in Account Data&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2263&quot;&gt;2263 MSC2263: Give homeservers the ability to handle their own 3PID registrations&#x2F;password resets&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2264&quot;&gt;2264 MSC2264: Add an unstable feature flag to MSC2140 for clients to detect support&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;2290&quot;&gt;2290 MSC2290: Separate Endpoints for Threepid Binding&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;matrix-org&#x2F;sydent
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;178&quot;&gt;178 Support for MSC2140&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;179&quot;&gt;179 Support testing with matrix-is-tester&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;180&quot;&gt;180 Support for MSC2140&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;181&quot;&gt;181 Deny bindings to anything other than the mxid you&#x27;re authed as&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;184&quot;&gt;184 Hash 3PID lookups&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;186&quot;&gt;186 Don&#x27;t fail the unbind request if the binding doesn&#x27;t exist&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;187&quot;&gt;187 Add more tweaks to terms branch&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;189&quot;&gt;189 Redact looked-up threepids from the application logs.&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;191&quot;&gt;191 Add OpenID auth to 3PID hash lookup&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;197&quot;&gt;197 Have &#x27;mappings&#x27; contain medium as well as address&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;198&quot;&gt;198 Throw exception on bad args &amp;amp; catch in wrapper&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;199&quot;&gt;199 Return algorithm, lookup_pepper in M_INVALID_PEPPER response&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;200&quot;&gt;200 Support MSC2140 register&#x2F;terms endpoints&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;201&quot;&gt;201 Port v1 endpoints to v2&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;202&quot;&gt;202 Deny bindings to anything other than the mxid you&#x27;re authed as&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;204&quot;&gt;204 Fix the signing servlet&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;205&quot;&gt;205 Correct API v1 path check in get_args&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;206&quot;&gt;206 Fix terms POST&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;207&quot;&gt;207 Deploy policy file&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;208&quot;&gt;208 Remove PII logging from log-level INFO&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;pull&#x2F;213&quot;&gt;213 Delete threepid assocs on unbind and remove existing with migration&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;217&quot;&gt;217 Allow non-matrix.org MXIDs via v2 only once terms are enabled&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;218&quot;&gt;218 Unbind fails to remove the binding on matrix.org IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;220&quot;&gt;220 Unbind fails to work for bindings where it was attempted with #213&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;192&quot;&gt;192 Sydent doesn&#x27;t delete 3PIDs from DB on unbind&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;matrix-org&#x2F;synapse
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;1287&quot;&gt;1287 We need to actually censor redactions from the DB (SYN-284)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5751&quot;&gt;5751 Make homeservers able to handle registration-with-email without depending on an Identity Server&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5786&quot;&gt;5786 Support IS v2 API with authentication for requests proxied to the IS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5827&quot;&gt;5827 Add 3PID unbind API for MSC2140&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5835&quot;&gt;5835 [1&#x2F;2] Allow homeservers to send registration emails | Sending the email&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5861&quot;&gt;5861 Use the v2 lookup API for 3PID invites&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5862&quot;&gt;5862 Allow account owners to rebind 3PIDs as in MSC2229&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5868&quot;&gt;5868 Add flag in &#x2F;versions for whether clients should send id_server params&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5874&quot;&gt;5874 Placeholder issue for privacy migration path&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5875&quot;&gt;5875 Remove trusted_third_party_id_servers functionality&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5876&quot;&gt;5876 Replace trust_identity_server_for_password_resets with account_threepid_delegate&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5892&quot;&gt;5892 Switch to using v2 Identity Service APIs other than lookup (MSC 2140)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5897&quot;&gt;5897 Use the v2 lookup API for 3PID invites&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5927&quot;&gt;5927 Add a m.id_access_token flag to unstable_features&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5928&quot;&gt;5928 Split account_threepid_handler into a msisdn and email versions&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5929&quot;&gt;5929 Use account_threepid_delegate for sending SMS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5930&quot;&gt;5930 Add m.id_access_token flag&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5934&quot;&gt;5934 Censor redactions in DB after a month&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5935&quot;&gt;5935 Use federation blacklist for requests to identity servers&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5937&quot;&gt;5937 Revert &quot;Use the v2 lookup API for 3PID invites&quot;&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5940&quot;&gt;5940 [2&#x2F;2] Allow homeservers to send registration emails | Accepting the verification&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5945&quot;&gt;5945 Revert &quot;Add m.id_access_token flag&quot;&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5948&quot;&gt;5948 Support v2 Identity Server APIs&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5964&quot;&gt;5964 Remove bind_email and bind_msisdn&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5968&quot;&gt;5968 Set m.require_identity_server to always be False&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5969&quot;&gt;5969 Change account_threepid_delegate to a dictionary&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5972&quot;&gt;5972 Add m.require_identity_server to &#x2F;versions unstable_flags&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5974&quot;&gt;5974 Add m.id_access_token to &#x2F;versions unstable_features (MSC2264)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5976&quot;&gt;5976 Use the v2 Identity Service API for lookups (MSC2134 + MSC2140)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5979&quot;&gt;5979 v2 3PID Invites (part of MSC2140)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5980&quot;&gt;5980 Add POST &#x2F;_matrix&#x2F;client&#x2F;r0&#x2F;account&#x2F;3pid&#x2F;unbind (MSC2140)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5987&quot;&gt;5987 Allow Synapse to send registration emails + choose Synapse or an external server to handle 3pid validation&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;5996&quot;&gt;5996 Allow users to rebind 3pids they own (MSC2229)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6000&quot;&gt;6000 Use the federation blacklist for requests to untrusted Identity Servers&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6011&quot;&gt;6011 Use account_threepid_delegate for 3pid validation&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6013&quot;&gt;6013 Fix existing v2 identity server calls (MSC2140)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6042&quot;&gt;6042 Allow HS to send emails when adding an email to the HS&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6043&quot;&gt;6043 Implement MSC2290&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6044&quot;&gt;6044 Add an unstable feature flag for separate add&#x2F;bind 3pid APIs&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6062&quot;&gt;6062 Use unstable prefix for 3PID unbind API&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6067&quot;&gt;6067 Drop support for bind param on POST &#x2F;account&#x2F;3pid (MSC2290)&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;6076&quot;&gt;6076 Synapse doesn&#x27;t give clients a submit_url on requestToken breaking msisdn adding&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6078&quot;&gt;6078 Add POST submit_token endpoint for MSISDN&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6079&quot;&gt;6079 Add submit_url response parameter to msisdn &#x2F;requestToken&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;6087&quot;&gt;6087 Remove hardcoded defaults of matrix.org and vector.im in configuration&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;pull&#x2F;6090&quot;&gt;6090 Explicitly log when a homeserver does not have a trusted key server configured&lt;&#x2F;a&gt;(done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;6096&quot;&gt;6096 Riot Web expects the email validation next_link to have the sid appended&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;6100&quot;&gt;6100 Remove email from registration flows if it’s unsupported&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;6103&quot;&gt;6103 _check_threepid in auth.py incorrect for MSISDN&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;6045&quot;&gt;6045 Support Client-Server API r0.6.0&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;1263&quot;&gt;1263 When we redact events, any mxc content they refer to should be redacted too (SYN-216)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;4565&quot;&gt;4565 Metadata resistance.&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;6086&quot;&gt;6086 Fetch signing-keys directly from servers before falling back to the trusted_key_servers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;phase:2
&lt;ul&gt;
&lt;li&gt;vector-im&#x2F;riot-web
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;4913&quot;&gt;4913 Option for homeservers to set a default integration manager&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10161&quot;&gt;10161 Store Integration Manager preferences in account data and allow user to change them somewhere sensible&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10967&quot;&gt;10967 Disconnect from identity server fails&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10443&quot;&gt;10443 Remove v1 IS API fallbacks once servers are updated&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10557&quot;&gt;10557 Prompt users each time before sending data to an Identity Server that doesn&#x27;t have a terms of service (unless you have actively set that IS in your account data).&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10696&quot;&gt;10696 Allow users to disconnect from an integration manager entirely in the same way that we support doing this for identity servers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10909&quot;&gt;10909 Unable to disconnect from IS if the server is unavailable&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10936&quot;&gt;10936 Refine submit_url handling to only activate with separate add and bind&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;vector-im&#x2F;riot-ios
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2711&quot;&gt;2711 Provide a better UX for users considering sharing their contact list with an IS to discover people they know already using Matrix&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;vector-im&#x2F;riot-android
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3282&quot;&gt;3282 Checking email invite account is unclear when no IS set&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-android&#x2F;issues&#x2F;3323&quot;&gt;3323 Post MSC2290 bug &#x2F; Clicking on the validation mail link fails registration&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;matrix-org&#x2F;matrix-doc
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;1957&quot;&gt;1957 MSC1957: Integration manager discovery&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;matrix-org&#x2F;sydent
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;sydent&#x2F;issues&#x2F;196&quot;&gt;196 Remove the lookup_hash field from local_threepid_associations&lt;&#x2F;a&gt; (in progress)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;matrix-org&#x2F;synapse
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5881&quot;&gt;5881 Remove trust_identity_server_for_password_resets and account_threepid_delegate options&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;phase:3
&lt;ul&gt;
&lt;li&gt;vector-im&#x2F;riot-web
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10563&quot;&gt;10563 Add better domain for turn.matrix.org use as STUN server&lt;&#x2F;a&gt; (done)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10087&quot;&gt;10087 Prompt to accept integration manager policies on registration&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10167&quot;&gt;10167 Present an aggregated terms of service dialogue at registration if possible&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10168&quot;&gt;10168 If a user has disabled the identity server integration on their account, we should make invite user handle this nicely&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10401&quot;&gt;10401 Invite new users to publish their threepids to the identity server&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10422&quot;&gt;10422 Use more contextual prompt for integration manager polices on use&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10453&quot;&gt;10453 Log out from IM on Riot log out and IM removal&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10455&quot;&gt;10455 Log out from IS on Riot log out and IS removal&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10487&quot;&gt;10487 Store the date of users having read and accepted the IM policies in the IM db&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10488&quot;&gt;10488 Store the date of users having read and accepted the IS policies in the IS db&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10498&quot;&gt;10498 Terms test scalar requires the legacy ?v query param on the new account route&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10575&quot;&gt;10575 We should show the &#x27;must configure TURN&#x27; warning when a call fails, even after using the fallback turn.matrix.org&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10615&quot;&gt;10615 Change all IS access token APIs to use getIdentityAccessToken only&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10671&quot;&gt;10671 riot submits sign-ed25519 requests as POST requests with params in query string and empty body&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10746&quot;&gt;10746 &#x2F;invite doesn&#x27;t force terms with older homeservers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10830&quot;&gt;10830 Show IS policy links in user settings somewhere.&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-web&#x2F;issues&#x2F;10950&quot;&gt;10950 Unhelpful 400 error when adding MSISDN and server doesn’t delegate&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;vector-im&#x2F;riot-ios
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vector-im&#x2F;riot-ios&#x2F;issues&#x2F;2710&quot;&gt;2710 Show IS policy links in user settings somewhere.&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;matrix-org&#x2F;matrix-doc
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;issues&#x2F;447&quot;&gt;447 We need a way to be able to expire data from a HS. (SPEC-141)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;matrix-org&#x2F;synapse
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;issues&#x2F;5830&quot;&gt;5830 &lt;code&gt;pushers&lt;&#x2F;code&gt; table contains user device names, which may include user real names&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>Publishing the Backend Roadmap</title>
    <published>2019-02-15T00:00:00+00:00</published>
    <updated>2019-02-15T00:00:00+00:00</updated>
    <author>
      <name>Neil Johnson</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2019/02/15/publishing-the-backend-roadmap/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2019/02/15/publishing-the-backend-roadmap/</id>
    <content type="html">&lt;p&gt;Good people,&lt;&#x2F;p&gt;
&lt;p&gt;2019 is a big year for Matrix, in the next month we will have shipped:&lt;&#x2F;p&gt;
&lt;ul&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Matrix spec 1.0 (including the first stable release of the Server to Server Spec)
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Synapse 1.0
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Riot 1.0
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
This is huge in itself, but is really only the beginning, and now we want to grow the ecosystem as quickly as possible. This means landing a mix of new features, enhancing existing ones, some big performance improvements as well as generally making life easier for our regular users, homeserver admins and community developers.
&lt;p&gt;Today we are sharing the Matrix core team&#x27;s backend roadmap. The idea is that this will make it easier for anyone to understand where the project is going, what we consider to be important, and why.&lt;&#x2F;p&gt;
&lt;p&gt;To see the roadmap in its full glory, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;orgs&#x2F;matrix-org&#x2F;projects&#x2F;9&quot;&gt;take a look here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-is-a-roadmap-and-why-is-it-valuable&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-is-a-roadmap-and-why-is-it-valuable&quot; aria-label=&quot;Anchor link for: what-is-a-roadmap-and-why-is-it-valuable&quot;&gt;🔗&lt;&#x2F;a&gt;What is a roadmap and why is it valuable?&lt;&#x2F;h3&gt;
&lt;p&gt;A roadmap is a set of high level projects that the team intend to work on and a rough sense of the relative priority. It is essential to focus on specific goals, which inevitably means consciously not working on other initiatives.&lt;&#x2F;p&gt;
&lt;p&gt;Our roadmap is not a delivery plan - there are explicitly no dates. The reason for this is that we know that other projects will emerge, developers will be needed to support other urgent initiatives, matrix.org use continues to grow exponentially and will require performance tweaking.&lt;&#x2F;p&gt;
&lt;p&gt;So simply, based on what we know now, this is the order we will work on our projects.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;why-are-we-sharing-it&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-are-we-sharing-it&quot; aria-label=&quot;Anchor link for: why-are-we-sharing-it&quot;&gt;🔗&lt;&#x2F;a&gt;Why are we sharing it?&lt;&#x2F;h3&gt;
&lt;p&gt;We already share our &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;orgs&#x2F;matrix-org&#x2F;projects&#x2F;8&quot;&gt;day to day todo list&lt;&#x2F;a&gt;, and of course our commit history, but it can be difficult for a casual observer to see the bigger picture from such granular data. The purpose of sharing is that we want anyone from the community to understand where our priorities lie.&lt;&#x2F;p&gt;
&lt;p&gt;We are often asked ‘Why are you not working on X, it is really important&#x27; where the answer is often ‘We agree that X is really important, but A, B and C are more important and must come first&#x27;.&lt;&#x2F;p&gt;
&lt;p&gt;The point of sharing the roadmap is to make that priority trade off more transparent and consumable.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-did-we-build-it&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-did-we-build-it&quot; aria-label=&quot;Anchor link for: how-did-we-build-it&quot;&gt;🔗&lt;&#x2F;a&gt;How did we build it?&lt;&#x2F;h3&gt;
&lt;p&gt;The core contributors to Synapse and Dendrite are 6 people, of 5 nationalities spread across 3 locations. After shipping the &lt;a href=&quot;&#x2F;docs&#x2F;spec&#x2F;server_server&#x2F;r0.1.1.html&quot;&gt;r0 release of the Server to Server spec&lt;&#x2F;a&gt; last month we took some time to step back and have a think about what to do after Synapse 1.0 lands. This meant getting everyone in one place to talk it through.&lt;&#x2F;p&gt;
&lt;p&gt;We also had Ben (benpa) contribute from a community perspective and took input from speaking to so many of you at FOSDEM.&lt;&#x2F;p&gt;
&lt;p&gt;In the end we filled a wall with post-its, each post-it representing a sizeable project. The position of the post-it was significant in that the vertical axis being a sense of how valuable we thought the task would be, and the horizontal axis being a rough guess on how complex we considered it to be.&lt;&#x2F;p&gt;
&lt;p&gt;We found this sort of grid approach to be really helpful in determining relative priority.&lt;&#x2F;p&gt;
&lt;p&gt;After many hours and plenty of blood, sweat and tears we ended up with something we could live with and wrote it up in the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;orgs&#x2F;matrix-org&#x2F;projects&#x2F;9&quot;&gt;shared board&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2019&#x2F;02&#x2F;IMG_2247.avif&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-3996&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2019&#x2F;02&#x2F;IMG_2247-300x225.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;225&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2019&#x2F;02&#x2F;IMG_2245.avif&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-3990&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2019&#x2F;02&#x2F;IMG_2245-300x225.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;225&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;and-this-is-written-in-blood-right&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#and-this-is-written-in-blood-right&quot; aria-label=&quot;Anchor link for: and-this-is-written-in-blood-right&quot;&gt;🔗&lt;&#x2F;a&gt;And this is written in blood right?&lt;&#x2F;h3&gt;
&lt;p&gt;Not at all (it&#x27;s written in board marker). This is simply a way to express our plan of action and we are likely to make changes to it dynamically. However, this means that at any given moment, if someone wants to know what we are working on then the roadmap is the place to go.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;but-wait-i-want-to-know-more&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#but-wait-i-want-to-know-more&quot; aria-label=&quot;Anchor link for: but-wait-i-want-to-know-more&quot;&gt;🔗&lt;&#x2F;a&gt;But wait I want to know more!&lt;&#x2F;h3&gt;
&lt;p&gt;Here is a video of myself and Matthew to talk you through the projects&lt;&#x2F;p&gt;
&lt;noscript&gt;
  Today&#x27;s Matrix Live:
  &lt;a href=&quot;https:&#x2F;&#x2F;youtube.com&#x2F;watch?v=LfyQ6cNGbLk&quot;&gt;
    https:&#x2F;&#x2F;youtube.com&#x2F;watch?v=LfyQ6cNGbLk
  &lt;&#x2F;a&gt;
&lt;&#x2F;noscript&gt;
&lt;youtube-player video-id=&quot;LfyQ6cNGbLk&quot;&gt;&lt;&#x2F;youtube-player&gt;
&lt;h3 id=&quot;interesting-but-i-have-questions&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#interesting-but-i-have-questions&quot; aria-label=&quot;Anchor link for: interesting-but-i-have-questions&quot;&gt;🔗&lt;&#x2F;a&gt;Interesting, but I have questions ...&lt;&#x2F;h3&gt;
&lt;p&gt;Any feedback gratefully received, come and ask questions in &lt;a href=&quot;https:&#x2F;&#x2F;matrix.to&#x2F;#&#x2F;#synapse:matrix.org&quot;&gt;#synapse&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;matrix.to&#x2F;#&#x2F;#dendrite:matrix.org&quot;&gt;#dendrite&lt;&#x2F;a&gt; or feel free to ping me direct at @neilj:matrix.org&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>Porting Synapse to Python 3</title>
    <published>2018-12-21T00:00:00+00:00</published>
    <updated>2018-12-21T00:00:00+00:00</updated>
    <author>
      <name>Neil Johnson</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2018/12/21/porting-synapse-to-python-3/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2018/12/21/porting-synapse-to-python-3/</id>
    <content type="html">&lt;p&gt;Matrix&#x27;s reference homeserver, Synapse, is written in Python and uses the Twisted networking framework to power its bitslinging across the Internet. The Python version used has been strictly Python 2.7, the last supported version of Python 2, but as of this week that changes! Since Twisted and our other upstream dependencies now support the newest version of Python, Python 3, we are now able to finish the jump and port Synapse to use it by default. The port has been done in a backwards compatible way, written in a subset of Python that is usable in both Python 2 and Python 3, meaning your existing Synapse installs still work on Python 2, while preparing us for a Python 3 future.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-port&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-port&quot; aria-label=&quot;Anchor link for: why-port&quot;&gt;🔗&lt;&#x2F;a&gt;Why port?&lt;&#x2F;h2&gt;
&lt;p&gt;Porting Synapse to Python 3 prepares Synapse for a post-Python 2 world, currently scheduled for 2020. After the 1st of January in 2020, Python 2 will no longer be supported by the core Python developers and no bugfixes (even critical security ones) will be issued. As the security of software depends very much on the runtime and libraries it is running on top of, this means that by then all Python 2 software in use should have moved to Python 3 or other runtimes.&lt;&#x2F;p&gt;
&lt;p&gt;The Python 3 port has benefits other than just preparing for the End of Life of Python 2.7. Successive versions of Python 3 have improved the standard library, provided newer and clearer syntax for asynchronous code, added opt-in static typing to reduce bugs, and contained incremental performance and memory management improvements. These features, once Synapse stops supporting Python 2, can then be fully utilised to make Synapse&#x27;s codebase clearer and more performant. One bonus that we get immediately, though, is Python 3&#x27;s memory compaction of Unicode strings. Rather than storing as UCS-2&#x2F;UTF-16 or UCS-4&#x2F;UTF-32, it will instead store it in the smallest possible representation giving a 50%-75% memory improvement for strings only containing Latin-1 characters, such as nearly all dictionary keys, hashes, IDs, and a large proportion of messages being processed from English speaking countries. Non-English text will also see a memory improvement, as it can be commonly stored in only two bytes instead of the four in a UCS-4 “wide” Python 2 build.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;i&gt;Editor&#x27;s note: If you were wondering how this fits in with Dendrite (the next-gen golang homeserver): our plan is to use Synapse as the reference homeserver for all the current work going on with landing a 1.0 release of the Matrix spec: it makes no sense to try to iterate and converge on 1.0 on both Synapse and Dendrite in parallel. In order to prove that the 1.0 spec is indeed fit for purpose we then also need Synapse to exit beta and hit a 1.0 too, hence the investment to get it there. It&#x27;s worth noting that over the last year we&#x27;ve been plugging away solidly improving Synapse in general (especially given the increasing number of high-profile deployments out there), so we&#x27;re committed to getting Synapse to a formal production grade release and supporting it in the long term. Meanwhile, Dendrite development is still progressing - currently acting as a place to experiment with more radical blue-sky architectural changes, especially in low-footprint or even clientside homeservers. We expect it to catch up with Synapse once 1.0 is out the door; and meanwhile Synapse is increasingly benefiting from performance work inspired by Dendrite.
&lt;&#x2F;i&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;when-will-the-port-be-released&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-will-the-port-be-released&quot; aria-label=&quot;Anchor link for: when-will-the-port-be-released&quot;&gt;🔗&lt;&#x2F;a&gt;When will the port be released?&lt;&#x2F;h2&gt;
&lt;p&gt;The port is has been released in a “production ready” form in &lt;a href=&quot;&#x2F;blog&#x2F;2018&#x2F;12&#x2F;20&#x2F;synapse-0-34-0-released&#x2F;&quot;&gt;Synapse 0.34.0&lt;&#x2F;a&gt;, supporting Python 3.5, 3.6, and 3.7. This will work on installations with and without workers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-s-it-like-in-the-real-world&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-s-it-like-in-the-real-world&quot; aria-label=&quot;Anchor link for: what-s-it-like-in-the-real-world&quot;&gt;🔗&lt;&#x2F;a&gt;What&#x27;s it like in the real world?&lt;&#x2F;h2&gt;
&lt;p&gt;Beta testers of the Python 3 port have reported lower memory usage, including lower memory “spikes” and slower memory growth. You can see this demonstrated on matrix.org:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;12&#x2F;image3.png&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-3830&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;12&#x2F;image3-1024x223.png&quot; alt=&quot;&quot; width=&quot;1024&quot; height=&quot;223&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;See 10&#x2F;15, ~20:00 for the Python 3 migration. This is on some of the Synchrotrons on matrix.org.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;12&#x2F;image1.png&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-3824&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;12&#x2F;image1-1024x237.png&quot; alt=&quot;&quot; width=&quot;1024&quot; height=&quot;237&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;See ~11&#x2F;8 for the Python 3 migration. This is on the Synapse master on matrix.org.&lt;&#x2F;p&gt;
&lt;p&gt;We have also noticed some better CPU utilisation:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;12&#x2F;image2.png&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-3822&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;12&#x2F;image2-1024x296.png&quot; alt=&quot;&quot; width=&quot;1024&quot; height=&quot;296&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;span&gt;
See 21:30 for the migration of federation reader 1, and 21:55 for the others. The federation reader is a particular pathological case, where the replacement of lists with iterators internally on Python 3 has given us some big boosts.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;12&#x2F;image4.png&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-3829&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;12&#x2F;image4-1024x296.png&quot; alt=&quot;&quot; width=&quot;1024&quot; height=&quot;296&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;See 10&#x2F;15, 4:00.The CPU utilisation has gone down on synchrotron 1 after the Python 3 migration, but not as dramatically as the federation reader. Synchrotron 3 was migrated a few days later.&lt;&#x2F;p&gt;
&lt;p&gt;As some extra data-points, my personal HS consumes about 300MB now at initial start, and grows to approximately 800MB -- under Python 2 the growth would be near-immediate to roughly 1.4GB.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;where-to-from-here&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#where-to-from-here&quot; aria-label=&quot;Anchor link for: where-to-from-here&quot;&gt;🔗&lt;&#x2F;a&gt;Where to from here?&lt;&#x2F;h2&gt;
&lt;p&gt;Python 2 is still a supported platform for running Synapse for the time being. We plan on ending mainstream support on 1st April 2019, where upon Python 3.5+ will be the only officially supported platform. Additionally, we will give notice ahead of time once we are ready to remove Python 2.7 compatibility from the codebase (which will be no sooner than 1st April). Although slightly inconvenient, we hope that this gives our users and integrators adequate time to migrate, whilst giving us the flexibility to use modern Python features and make Synapse a better piece of software to help power the Matrix community.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-can-i-try-it&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-can-i-try-it&quot; aria-label=&quot;Anchor link for: how-can-i-try-it&quot;&gt;🔗&lt;&#x2F;a&gt;How can I try it?&lt;&#x2F;h2&gt;
&lt;p&gt;The port is compatible with existing homeservers and configurations, so if you install Synapse inside a Python 3 virtualenv, you can run it from there. Of course, this differs based on your installation method, operating system, and what version of Python 3 you wish to use. Full upgrade notes live &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;synapse&#x2F;blob&#x2F;release-v0.34.0&#x2F;UPGRADE.rst#upgrading-to-v0340&quot;&gt;here&lt;&#x2F;a&gt; but if you&#x27;re having problems or want to discuss specific packagings of Synapse please come ask in &lt;a href=&quot;https:&#x2F;&#x2F;matrix.to&#x2F;#&#x2F;#synapse:matrix.org&quot;&gt;#synapse:matrix.org&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;thanks&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#thanks&quot; aria-label=&quot;Anchor link for: thanks&quot;&gt;🔗&lt;&#x2F;a&gt;Thanks&lt;&#x2F;h2&gt;
&lt;p&gt;Many thanks go to fellow Synapse developers Erik and Rich for code review, as well as community contributors such as notafile and krombel for laying the foundations many months ago allowing this port to happen. Without them, this wouldn&#x27;t have happened.&lt;&#x2F;p&gt;
&lt;p&gt;Happy Matrixing,&lt;&#x2F;p&gt;
&lt;p&gt;Amber Brown (hawkowl)&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>Olm 3.0.0 released!</title>
    <published>2018-10-25T00:00:00+00:00</published>
    <updated>2018-10-25T00:00:00+00:00</updated>
    <author>
      <name>Hubert Chathi</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2018/10/25/olm-3-0-0-released/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2018/10/25/olm-3-0-0-released/</id>
    <content type="html">&lt;p&gt;Olm 3.0.0 has been released, which features several big changes. It can be downloaded from &lt;a href=&quot;https:&#x2F;&#x2F;git.matrix.org&#x2F;git&#x2F;olm&#x2F;&quot;&gt;https:&#x2F;&#x2F;git.matrix.org&#x2F;git&#x2F;olm&#x2F;&lt;&#x2F;a&gt;. The npm package for JavaScript can be downloaded from &lt;a href=&quot;&#x2F;packages&#x2F;npm&#x2F;olm&#x2F;olm-3.0.0.tgz&quot;&gt;https:&#x2F;&#x2F;matrix.org&#x2F;packages&#x2F;npm&#x2F;olm&#x2F;olm-3.0.0.tgz&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;python&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#python&quot; aria-label=&quot;Anchor link for: python&quot;&gt;🔗&lt;&#x2F;a&gt;Python&lt;&#x2F;h2&gt;
&lt;p&gt;The biggest change is the merge of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;poljar&#x2F;&quot;&gt;poljar&#x27;s&lt;&#x2F;a&gt; improved Python bindings. These bindings should be much easier to use for Python programmers, and are used by &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Zil0&#x2F;&quot;&gt;Zil0&#x27;s&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Zil0&#x2F;matrix-python-sdk&#x2F;tree&#x2F;e2e_sample&quot;&gt;E2E support in the Matrix Python SDK&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Since the binding API has changed, existing Python code will need to be rewritten in order to work with this release.&lt;&#x2F;p&gt;
&lt;p&gt;poljar has also included &lt;a href=&quot;https:&#x2F;&#x2F;poljar.github.io&#x2F;python-olm&#x2F;html&#x2F;index.html&quot;&gt;comprehensive documentation&lt;&#x2F;a&gt; for the new API.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cmake&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#cmake&quot; aria-label=&quot;Anchor link for: cmake&quot;&gt;🔗&lt;&#x2F;a&gt;CMake&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mujx&#x2F;&quot;&gt;mujx&lt;&#x2F;a&gt; contributed support for building olm using CMake. This should allow for easier building on different platforms. Currently the library can be built using either make or CMake. In the future, make support may be removed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;javascript&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#javascript&quot; aria-label=&quot;Anchor link for: javascript&quot;&gt;🔗&lt;&#x2F;a&gt;JavaScript&lt;&#x2F;h2&gt;
&lt;p&gt;The JavaScript bindings now use &lt;a href=&quot;https:&#x2F;&#x2F;webassembly.org&#x2F;&quot;&gt;WebAssembly&lt;&#x2F;a&gt; by default. WebAssembly is much faster than the previous &lt;a href=&quot;http:&#x2F;&#x2F;asmjs.org&#x2F;&quot;&gt;asm.js&lt;&#x2F;a&gt; build, and is supported by recent versions of the most popular browsers. For compatibility with browsers that do not support WebAssembly, the asm.js version is still provided.&lt;&#x2F;p&gt;
&lt;p&gt;Due to adding support for WebAssembly, the API had to be changed slightly.
There is now an &lt;code&gt;init&lt;&#x2F;code&gt; function that must be called before the library can be used. This function will return a promise that will resolve once the library is ready to be used. The &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-js-sdk&quot;&gt;matrix-js-sdk&lt;&#x2F;a&gt; has not yet been updated to do this, so users of matrix-js-sdk should continue using olm 2.x until it has been updated.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;key-backups&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#key-backups&quot; aria-label=&quot;Anchor link for: key-backups&quot;&gt;🔗&lt;&#x2F;a&gt;Key backups&lt;&#x2F;h2&gt;
&lt;p&gt;The public key API has been updated to support the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;1538&quot;&gt;proposal for server-side key backups&lt;&#x2F;a&gt;. More details on how to use these functions will be published in the future.&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>Matrix Spec Update August 2018</title>
    <published>2018-09-03T00:00:00+00:00</published>
    <updated>2018-09-03T00:00:00+00:00</updated>
    <author>
      <name>Matthew Hodgson</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2018/09/03/matrix-spec-update-august-2018/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2018/09/03/matrix-spec-update-august-2018/</id>
    <content type="html">&lt;h2 id=&quot;introducing-client-server-api-0-4-and-the-first-ever-stable-is-as-and-push-apis-spec-releases&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#introducing-client-server-api-0-4-and-the-first-ever-stable-is-as-and-push-apis-spec-releases&quot; aria-label=&quot;Anchor link for: introducing-client-server-api-0-4-and-the-first-ever-stable-is-as-and-push-apis-spec-releases&quot;&gt;🔗&lt;&#x2F;a&gt;Introducing Client Server API 0.4, and the first ever stable IS, AS and Push APIs spec releases!&lt;&#x2F;h2&gt;
&lt;p&gt;Hi folks,&lt;&#x2F;p&gt;
&lt;p&gt;As many know, we&#x27;ve been on a massive sprint to improve the spec - both fixing omissions where features have been implemented in the reference servers but were never formalised in the spec, and fixing bugs where the spec has thinkos which stop us from being able to ratify it as stable and thus fit for purpose .&lt;&#x2F;p&gt;
&lt;p&gt;In practice, our target has been to cut stable releases of all the primary Matrix APIs by the end of August - effectively declaring Matrix out of beta, at least at the specification level.  For context: historically only one API has ever been released as stable - the Client Server API, which was the result of a similar sprint back in Jan 2016. This means that the Server Server (SS) API, Identity Service (IS) API, Application Service (AS) API and Push Gateway API have never had an official stable release - which has obviously been problematic for those implementing them.&lt;&#x2F;p&gt;
&lt;p&gt;However, as of the end of Friday Aug 31, we&#x27;re proud to announce the first ever stable releases of the &lt;a href=&quot;&#x2F;docs&#x2F;spec&quot;&gt;IS, AS and Push APIs&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;docs&#x2F;spec&quot;&gt;&lt;img src=&quot;&#x2F;_matrix&#x2F;media&#x2F;v1&#x2F;download&#x2F;t2l.io&#x2F;587a1a86905b1e0e8f9342d76e57ffbe&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
To the best of our knowledge, these API specs are now complete and accurately describe all the current behaviour implemented in the reference implementations (sydent, synapse and sygnal) and are fit for purpose. Any deviation from the spec in the reference implementations should probably be considered a bug in the impl. All changes take the form of filling in spec omissions and adding clarifications to the existing behaviour in order to get things to the point that an independent party can implement these APIs without having to refer to anything other than the spec.&lt;&#x2F;p&gt;
&lt;p&gt;This is the result of a lot of work which spans the whole Spec Core Team, but has been particularly driven by TravisR, who has taken the lead on this whole mission to improve the spec.  Huge thanks are due to Travis for his work here, and also massive thanks to everyone who has &lt;del&gt;suffered&lt;&#x2F;del&gt; &lt;del&gt;endured&lt;&#x2F;del&gt; reviewed his PRs and contributed to the releases.  The spec is looking unrecognisably better for it - and Matrix 1.0 is feeling closer than ever!&lt;&#x2F;p&gt;
&lt;p&gt;Alongside the work on the IS&#x2F;AS&#x2F;Push APIs, there has also been a massive attempt to plug all the spec omissions in the Client Server API.  Historically the CS API releases have missed some of the newer APIs (and of course always miss the ones which postdate a given release), but we&#x27;ve released the APIs which &#x2F;have&#x2F; been specified as stable in order to declare them stable.  However, in this release we&#x27;ve tried to go through and fill in as many remaining gaps as possible.&lt;&#x2F;p&gt;
&lt;p&gt;The result is the release of &lt;a href=&quot;&#x2F;docs&#x2F;spec&#x2F;client_server&#x2F;r0.4.0.html&quot;&gt;Client Server API version 0.4&lt;&#x2F;a&gt;. This is a huge update - increasing the size of the CS API by ~40%. The biggest new stuff includes fully formalising support for end-to-end encryption (thanks to Zil0!), versioning for rooms (so we can upgrade rooms to new versions of the protocol), synchronised read markers, user directories, server ACLs, MSISDN 3rd party ids, and .well-known server discovery (not that it&#x27;s widely used yet), but for the full picture, best bet is to look at &lt;a href=&quot;&#x2F;docs&#x2F;spec&#x2F;client_server&#x2F;r0.4.0.html#changelog&quot;&gt;the changelog&lt;&#x2F;a&gt; (now managed by &lt;a href=&quot;https:&#x2F;&#x2F;pypi.org&#x2F;project&#x2F;towncrier&#x2F;&quot;&gt;towncrier&lt;&#x2F;a&gt;!).  It&#x27;s probably fair to say that the CS API is growing alarmingly large at this point - Chrome says that it&#x27;d be 223 A4 pages if printed. Our solution to this will be to refactor it somehow (and perhaps switch to a more compact representation of the contents).&lt;&#x2F;p&gt;
&lt;p&gt;Some things got deliberately missed from the CS 0.4 release: particularly membership Lazy Loading (because we&#x27;re still testing it out and haven&#x27;t released it properly in the wild yet), the various GDPR-specific APIs (because they may evolve a bit as we refine them since the original launch), finalising ID grammars in the overall spec (because this is surprisingly hard and subtle and we don&#x27;t want to rush it) and finally Communities (aka Groups), as they are still somewhat in flux.&lt;&#x2F;p&gt;
&lt;p&gt;Meanwhile, on the Server to Server API, there has also been a massive amount of work.  Since the beginning of July it&#x27;s
&lt;b&gt;tripled&lt;&#x2F;b&gt; in size as we&#x27;ve filled in the gaps, over the course of &amp;gt;200 commits (&amp;gt;150 of which from Travis).  If you take a look at the &lt;a href=&quot;&#x2F;docs&#x2F;spec&#x2F;server_server&#x2F;unstable.html&quot;&gt;current snapshot&lt;&#x2F;a&gt; it&#x27;s pretty unrecognisable from the historical draft; with the main changes being:&lt;&#x2F;p&gt;
&lt;ul&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Adding the new State Resolution algorithm to address flaws in the original one.  This has been where much of our time has gone - see &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;1441&quot;&gt;MSC1442&lt;&#x2F;a&gt; for full details.  Adopting the new algorithm requires rooms to be recreated; we&#x27;ll write more about this in the near future when we actually roll it out.
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Adding room versioning so we can upgrade to the new State Resolution algorithm.
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Everything is now properly expressed as Swagger (OpenAPI), just like the CS API
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Adding all the details for E2E encryption (including dependencies like to-device messaging and device-list synchronisation)
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Improvements in specifying how to authorize inbound events over federation
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Document federation APIs such as &#x2F;event_auth and &#x2F;query_auth and &#x2F;get_missing_events
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Document 3rd party invites over federation
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Document the &#x2F;user&#x2F;* federation endpoints
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Document Server ACLs
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Document read receipts over federation
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Document presence over federation
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Document typing notifications over federation
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Document content repository over federation
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Document room directory over federation
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;...and many many other minor bug fixes, omission fixes, and restructuring for coherency - see &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;issues&#x2F;1464&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;issues&#x2F;1464&lt;&#x2F;a&gt; for an even longer list :)
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
However, we haven&#x27;t finished it all: despite our best efforts we&#x27;re running slightly past the original target of Aug 31.  The current state of play for the r0 release overall (in terms of pending issues) is:
&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;09&#x2F;Screen-Shot-2018-09-03-at-16.56.18.png&quot;&gt;&lt;img class=&quot;aligncenter size-full wp-image-3525&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;09&#x2F;Screen-Shot-2018-09-03-at-16.56.18.png&quot; alt=&quot;&quot; width=&quot;576&quot; height=&quot;214&quot; &#x2F;&gt;&lt;&#x2F;a&gt;...and you can see the full breakdown over at the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;projects&#x2F;1&quot;&gt;public Github project dashboard&lt;&#x2F;a&gt;.
&lt;p&gt;The main stuff we still have remaining on the Server&#x2F;Server API at this point is:&lt;&#x2F;p&gt;
&lt;ul&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Better specifying how we validate inbound events. See &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;issues&#x2F;1646&quot;&gt;MSC1646&lt;&#x2F;a&gt; for details &amp; progress.
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Switching event IDs to be hashes. See &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;issues&#x2F;1640&quot;&gt;MSC1640&lt;&#x2F;a&gt; for details and progress.
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Various other remaining security considerations (e.g. how to handle malicious auth events in the DAG; how to better handle DoS situations).
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Merging in the changes to authoring m.room.power_levels (as per &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;issues&#x2F;1304&quot;&gt;MSC1304&lt;&#x2F;a&gt;)
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Formally specifying the remaining identifiers which lack a formal grammar - &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;1598&quot;&gt;MSC1597&lt;&#x2F;a&gt; and particularly room aliases (
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-doc&#x2F;pull&#x2F;1607&quot;&gt;MSC1608&lt;&#x2F;a&gt;)
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
The plan here is to continue speccing and implementing these at top priority (with Travis continuing to work fulltime on spec work), and we&#x27;ll obviously keep you up-to-date on progress.  Some of the changes here (e.g. event IDs) are quite major and we definitely want to implement them before speccing them, so we&#x27;re just going to have to keep going as fast as we can. Needless to say we want to cut an r0 of the S2S API alongside the others asap and declare Matrix out of beta (at least at the spec level :)
&lt;p&gt;In terms of visualising progress on this spec mission it&#x27;s interesting to look at the rate at which we&#x27;ve been closing PRs: this graph shows the total number of PRs which are in state ‘open&#x27; or ‘closed&#x27; on any given day:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;09&#x2F;Screen-Shot-2018-09-03-at-00.56.38.png&quot;&gt;&lt;img class=&quot;aligncenter size-large wp-image-3526&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;09&#x2F;Screen-Shot-2018-09-03-at-00.56.38-1024x722.png&quot; alt=&quot;&quot; width=&quot;1024&quot; height=&quot;722&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;...which clearly shows the original sprint to get the r0 of the CS API out the door at the end 2015, and then a more leisurely pace until the beginning of July 2018 since which the pace has picked up massively.  Other ways of looking at include the number of open issues...&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;09&#x2F;image-1.png&quot;&gt;&lt;img class=&quot;aligncenter size-large wp-image-3527&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;09&#x2F;image-1-1024x691.png&quot; alt=&quot;&quot; width=&quot;1024&quot; height=&quot;691&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
...or indeed the number of commits per week…&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;09&#x2F;Screen-Shot-2018-09-03-at-01.02.27.png&quot;&gt;&lt;img class=&quot;aligncenter wp-image-3528&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;09&#x2F;Screen-Shot-2018-09-03-at-01.02.27-1024x195.png&quot; alt=&quot;&quot; width=&quot;710&quot; height=&quot;135&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
...or the overall Github Project activity for August.  (It&#x27;s impressive to see Zil0 sneaking in there on second place on the commit count, thanks to all his GSoC work documenting E2E encryption in the spec as part of implementing it in matrix-python-sdk!)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;09&#x2F;Screen-Shot-2018-09-03-at-01.03.57.png&quot;&gt;&lt;img class=&quot;aligncenter wp-image-3529&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;09&#x2F;Screen-Shot-2018-09-03-at-01.03.57-1024x925.png&quot; alt=&quot;&quot; width=&quot;744&quot; height=&quot;672&quot; &#x2F;&gt;&lt;&#x2F;a&gt;
Anyway, enough numerology.  It&#x27;s worth noting that all of the dev for r0 has generally followed the proposed &lt;a href=&quot;&#x2F;blog&#x2F;2018&#x2F;06&#x2F;20&#x2F;towards-open-governance-for-matrix-org&#x2F;&quot;&gt;Open Governance Model for Matrix&lt;&#x2F;a&gt;, with the core spec team made up of both historical core team folk (erik, richvdh, dave &amp;amp; matthew), new core team folk (uhoreg &amp;amp; travis) and community folk (kitsune, anoa &amp;amp; mujx) working together to review and approve the changes - and we&#x27;ve been doing MSCs (albeit with an accelerated pace) for anything which we feel requires input from the wider community.  Once the Server&#x2F;Server r0 release is out the door we&#x27;ll be finalising the open governance model and switching to a slightly more measured (but productive!) model of spec development as outlined there.&lt;&#x2F;p&gt;
&lt;p&gt;Meanwhile, Matrix 1.0 gets ever closer.  With (almost) all this spec mission done, our plan is to focus more on improving the reference implementations - particularly performance in Synapse, 
UX in matrix-{&#x27;{&#x27;}react,ios,android{&#x27;}&#x27;}-sdk as used by Riot (especially for E2E encryption), and then declare a 1.0 and get back to implementing new features (particularly Editable Messages and Reactions) at last.&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;d like to thank everyone for your patience whilst we&#x27;ve been playing catch up on the spec, and hope you agree it&#x27;s been worth the effort :)&lt;&#x2F;p&gt;
&lt;p&gt;Matthew &amp;amp; the core spec team.&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>GSOC: Implementing End-to-End Encryption in the Matrix Python SDK</title>
    <published>2018-08-01T00:00:00+00:00</published>
    <updated>2018-08-01T00:00:00+00:00</updated>
    <author>
      <name>Ben Parsons</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2018/08/01/gsoc-implementing-end-to-end-encryption-in-the-matrix-python-sdk/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2018/08/01/gsoc-implementing-end-to-end-encryption-in-the-matrix-python-sdk/</id>
    <content type="html">&lt;p&gt;Following on from the previous post, we have an update from zil0 on his &lt;a href=&quot;https:&#x2F;&#x2F;summerofcode.withgoogle.com&#x2F;organizations&#x2F;6091058287476736&#x2F;#5468043765874688&quot;&gt;GSoC project&lt;&#x2F;a&gt;, which entailed implementing E2E support in the Matrix Python SDK.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;The goal of my project is to implement Matrix&#x27;s end-to-end encryption protocol in Python, as part of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-python-sdk&quot;&gt;matrix-python-sdk&lt;&#x2F;a&gt;. My mentors are Richard van der Hoff (richvdh) and Hubert Chathi (uhoreg).&lt;&#x2F;p&gt;
&lt;p&gt;It was easy to get started on the project, since the simple parts came first (adding API calls), and then the whole process to follow is documented in an &lt;a href=&quot;&#x2F;docs&#x2F;guides&#x2F;e2e_implementation.html&quot;&gt;implementation guide&lt;&#x2F;a&gt;, while there is also the reference implementation in JavaScript. And most importantly, the community is nice. :)&lt;&#x2F;p&gt;
&lt;p&gt;Some parts of the work consist in wrapping around the cryptographic primitives implemented in &lt;a href=&quot;https:&#x2F;&#x2F;git.matrix.org&#x2F;git&#x2F;olm&#x2F;&quot;&gt;libolm&lt;&#x2F;a&gt; (via &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;poljar&#x2F;python-olm&quot;&gt;Python bindings&lt;&#x2F;a&gt;), in order to handle encrypted events. Others are less straightforward, such as tracking device lists of users, or finding the right way to persist keys and related data between startups.&lt;&#x2F;p&gt;
&lt;p&gt;An interesting aspect of this project is that I am working on a new part of the Python SDK, while also having to integrate with existing code, which is a cool balance between freedom and guidelines.&lt;&#x2F;p&gt;
&lt;p&gt;As the encryption documentation is a bit outdated and incomplete, one (fun) difficulty is to look for information across old issues, Gdocs and source code (and asking my mentor when in doubt). For anyone trying to implement E2E, it should be better by the end of the project, as I am currently working on documenting the missing bits.&lt;&#x2F;p&gt;
&lt;p&gt;I have had a great experience so far. Working on an open source project differs from my previous coding experiences, as people are actually going to use what I write! I have learnt to think about the best design from a usability point of view, discuss different approaches, and I had to write tests and document my code, which sadly is not something I do on personal projects. I enjoyed reviews, and the discussions they led to. And of course I have learnt quite an interesting lot about the E2E voodoo, along with some new Python tricks.&lt;&#x2F;p&gt;
&lt;p&gt;Currently, the implementation is in a working state. Some of the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-python-sdk&#x2F;pulls?utf8=%E2%9C%93&amp;q=is%3Apr+author%3AZil0&quot;&gt;code&lt;&#x2F;a&gt; is merged, and some is awaiting review. It is possible to try it &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;matrix-python-sdk&#x2F;issues&#x2F;100#issuecomment-402508438&quot;&gt;here&lt;&#x2F;a&gt; before everything is merged.
The project will be finished in about one week, after some tidying up and when I release device verification and key sharing, which should be the last missing features compared to Riot.&lt;&#x2F;p&gt;
</content>
</entry>

    
    
<entry xml:lang="en">
    <title>Dendrite Progress Update</title>
    <published>2018-07-30T00:00:00+00:00</published>
    <updated>2018-07-30T00:00:00+00:00</updated>
    <author>
      <name>Ben Parsons</name>
    </author>
    <link rel="alternate" href="https://c956b204.matrix-website.pages.dev/blog/2018/07/30/dendrite-progress-update/" type="text/html"/>
    <id>https://c956b204.matrix-website.pages.dev/blog/2018/07/30/dendrite-progress-update/</id>
    <content type="html">&lt;p&gt;As you may know, for the last few months anoa (Andrew) and APWhiteHat have been working on Dendrite, the next generation Matrix homeserver, written in Go. We asked for an update on their progress, and Andrew provided the blog post below. Serious progress has been made on Dendrite this summer!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Hey everyone, my name is Andrew Morgan and I&#x27;ve been working full-time over the summer on Dendrite, our next-generation Matrix homeserver. Over the last two months, I&#x27;ve seen the project transform from a somewhat functioning toy server to a near-production-ready homeserver that is working towards complete feature support. I&#x27;ve appreciated the thought put into the project since day one, and enjoy the elegance of the multi-component design. Documentation is fairly decent at the moment, but comments are plentiful throughout the codebase, while the code itself tends towards simple and maintainable rather than complex and unmanageable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;application-service-integration&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#application-service-integration&quot; aria-label=&quot;Anchor link for: application-service-integration&quot;&gt;🔗&lt;&#x2F;a&gt;Application Service Integration&lt;&#x2F;h2&gt;
&lt;p&gt;The main focus of my time here has been on the implementation of application service support for Dendrite. Application services are external programs that act as privileged extensions to a homeserver, allowing such functionality as bots in rooms and bridges to third-party networks. Supporting application services requires a few different bits and pieces to be set up. Currently all planned features have a PR for them, with the bold items already merged:&lt;&#x2F;p&gt;
&lt;ul&gt;
 	&lt;li&gt;&lt;strong&gt;Sending events to application services&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
 	&lt;li&gt;&lt;strong&gt;Support user masquerading for events&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
 	&lt;li&gt;&lt;strong&gt;Support editing event timestamps&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
 	&lt;li&gt;Support room alias querying&lt;&#x2F;li&gt;
 	&lt;li&gt;Support user ID querying
&lt;&#x2F;li&gt;
 	&lt;li&gt;Support third party lookup proxying
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
As you can see a decent portion of the functionality is already in master! The rest will hopefully follow after some further back and forth.
&lt;h2 id=&quot;google-summer-of-code&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#google-summer-of-code&quot; aria-label=&quot;Anchor link for: google-summer-of-code&quot;&gt;🔗&lt;&#x2F;a&gt;Google Summer of Code&lt;&#x2F;h2&gt;
&lt;p&gt;I certainly haven&#x27;t been going at this all on my own. Alongside extensive help from Erik, who&#x27;s been mentoring me, our resident Google Summer of Code student, APWhiteHat, has been tackling feature after feature in Dendrite wherever he can find them. Application services received a good deal of help on client-server endpoint authentication side, however, APWhiteHat has mostly been focusing on federation and some other very useful pieces. While his GSoC period still has a week or so before its conclusion, he has so far implemented:&lt;&#x2F;p&gt;
&lt;ul&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Idempotency to roomserver event processing to prevent duplication
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Username auto generation
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Tokens library based on macaroons
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Lots of left-over federation stuff: state API &amp; get missing events being the major ones
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;AS support to clientapi auth
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;Typing server: handling of PUT &#x2F;typing by clientapi
&lt;&#x2F;li&gt;
 	&lt;li style=&quot;font-weight: 400;&quot;&gt;More typing server stuff on its way
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
From my perspective, APWhiteHat was an excellent developer to work with. He asked good questions and was quick to answer any myself or the community had as well. His code reviews were also very comprehensive. I learned a lot from working with him and everyone else :)
&lt;h2 id=&quot;opentracing-and-prometheus-monitoring&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#opentracing-and-prometheus-monitoring&quot; aria-label=&quot;Anchor link for: opentracing-and-prometheus-monitoring&quot;&gt;🔗&lt;&#x2F;a&gt;OpenTracing and Prometheus Monitoring&lt;&#x2F;h2&gt;
&lt;p&gt;Placing any large server into a production environment requires extensive monitoring capabilities in order to ensure operations are running smoothly. To that effect, Dendrite has been both the addition of OpenTracing and Prometheus support. Prometheus, also used heavily in Synapse, allows a homeserver operator to track a wide range of data including endpoint usage, resource management as well as user statistics over any given range of time.&lt;&#x2F;p&gt;
&lt;p&gt;In Dendrite, we are taking this one step further by introducing &lt;a href=&quot;https:&#x2F;&#x2F;opentracing.io&#x2F;&quot;&gt;OpenTracing&lt;&#x2F;a&gt;, a language and platform-agnostic framework for tracking the journey of an endpoint call from incoming request to outgoing response, with every method, hierarchy change and database call in between. It will be immensely useful in tracking down performance issues, as well as providing insight into the most critical paths throughout the codebase and where we should focus most of our optimization efforts on. It also comes with a lovely dashboard courtesy of &lt;a href=&quot;https:&#x2F;&#x2F;www.jaegertracing.io&#x2F;&quot;&gt;Jaeger&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;07&#x2F;image1.png&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-3432&quot; src=&quot;&#x2F;blog&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;07&#x2F;image1-1024x527.png&quot; alt=&quot;&quot; width=&quot;1024&quot; height=&quot;527&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;community&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#community&quot; aria-label=&quot;Anchor link for: community&quot;&gt;🔗&lt;&#x2F;a&gt;Community&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ve also seen some encouraging interest and development work from the community in the past couple months. While PR review from our own side is admittedly slow due to our focus on getting the foundational work in place, that hasn&#x27;t stopped both old and new developers from sending in PRs and performing code reviews. A huge thank you to everyone involved! From this we&#x27;ve gotten API implementations and application service fixes from @turt2live, &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;matrixdotorg&#x2F;status&#x2F;1022887733931520001&quot;&gt;an end-to-end encryption implementation from @fadeAce&lt;&#x2F;a&gt;, filtering support from @CromFr, and some PRs and numerous helpful review comments from @krombel.&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;ve also started to see some people running Dendrite in live environments, which is incredibly exciting for us to see! While Dendrite is not considered production-ready yet (though it moves closer every day), if you are interested in giving it a go please consult the quickstart &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matrix-org&#x2F;dendrite&#x2F;blob&#x2F;master&#x2F;INSTALL.md&quot;&gt;installation guide&lt;&#x2F;a&gt;. We look forward to any feedback you may have!&lt;&#x2F;p&gt;
</content>
</entry>

    
    
</feed>
