<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>nikclayton</title>
    <link>https://nikclayton.writeas.com/</link>
    <description>Mastodon: &lt;a href=&#34;https://mastodon.social/@nikclayton&#34; rel=&#34;me&#34;&gt;https://mastodon.social/@nikclayton&lt;/a&gt;</description>
    <pubDate>Thu, 09 Apr 2026 08:56:56 +0000</pubDate>
    <item>
      <title>Using QGIS to filter routes by minimum elevation</title>
      <link>https://nikclayton.writeas.com/using-qgis-to-filter-routes-by-minimum-elevation?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[After yesterday&#39;s post about finding snowshoe routes using Swiss OpenData and QGIS I had one open question: how to also filter the routes by their minimum elevation?&#xA;&#xA;As winter turns to spring and the snow starts melting this is necessary to find routes that probably still have snow on them.&#xA;&#xA;The data from opendata.swiss has the route geometry, and various pre-existing fields for the route length, maximum ascent, and so on, but there is no direct field that contains the route&#39;s minimum elevation, so it cannot be used directly in a filter.&#xA;&#xA;Assuming that this is the sort of thing that must be both possible and straightforward, I asked the QGIS community on the Fediverse. @tlohde@fediscience.org was kind enough to reply, and this post is adapted from their suggestions.&#xA;&#xA;The rest of this post assumes you have already followed the steps in Finding snowshoe routes using Swiss OpenData and QGIS.&#xA;&#xA;Outline&#xA;&#xA;We are going to:&#xA;&#xA;Create a new column in the snowshoe data to contain the minimum elevation of each route.&#xA;Apply a QGIS function, zmin, to populate this column.&#xA;Update the existing filter to exclude routes with a minimum elevation below 1,500 metres.&#xA;&#xA;Creating and populating the column&#xA;&#xA;Open the &#34;Field calculator&#34; for the snowshoe attribute table.&#xA;&#x9;Open the layer menu by right clicking the &#34;schneeschuhwanderwege2056.gpk&#34; layer in the layer pane (bottom left)&#xA;&#x9;From the menu click &#34;Open Attribute Table&#34; to open the attribute table pane below the map.&#xA;&#x9;Open the &#34;Field Calculator by clicking the &#34;Edit&#34; button and then the &#34;Open field calculator&#34; button in the toolbar above the attribute table&#xA;open-attribute-table.png&#xA;Create a new &#34;minelev&#34; column in the data.&#xA;&#x9;Ensure &#34;Create a new field&#34; is checked.&#xA;&#x9;Enter &#34;minelev&#34; in the &#34;Output field name&#34; field&#xA;&#x9;Enter &#34;zmin($geometry)&#34; in the &#34;Expression&#34; field&#xA;&#x9;Click &#34;OK&#34;&#xA;field-calculator-minelev.png&#xA;&#xA;This has created a new column in the snow show data called &#34;minelev&#34;, with a value calculated as the lowest Z point (elevation) in the route geometry for that row.&#xA;&#xA;You can verify this in the attribute table. Scroll the table to the right and you will see the new minelev column at the end.&#xA;&#xA;Exclude routes below 1,500 metres&#xA;&#xA;Click the &#34;Edit&#34; button in the attribute pane to disable editing.&#xA;Open the layer menu by right clicking the &#34;schneeschuhwanderwege2056.gpk&#34; layer in the layer pane.&#xA;Choose &#34;Filter...&#34; to open the Query Builder.&#xA;Click the &#34;Test&#34; button.&#xA;&#x9;If you are using the query from yesterday you will see a dialog message, &#34;The where clause returned 39 row(s)&#34;. If you are using a different query the number of rows will be different.&#xA;&#x9;Click OK to dismiss the dialog.&#xA;Edit the query to add a final clause, AND minelev   = 1500. query-builder-min_elev.png&#xA;Click the &#34;Test&#34; button again.&#xA;&#x9;If you where using the query from yesterday you will see a dialog message, &#34;The where clause returned 9 row(s)&#34;. So 30 routes that dip below 1,500 metres have been removed. If you were using a different query you will see a different number of results.&#xA;&#x9;Click OK to dismiss the dialog.&#xA;Click OK to dismiss the Query Builder&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>After <a href="https://write.as/nikclayton/finding-showshoe-routes-using-swiss-opendata-and-qgis" rel="nofollow">yesterday&#39;s post about finding snowshoe routes using Swiss OpenData and QGIS</a> I had one open question: how to also filter the routes by their minimum elevation?</p>

<p>As winter turns to spring and the snow starts melting this is necessary to find routes that probably still have snow on them.</p>

<p>The data from <a href="https://www.opendata.swiss/en" rel="nofollow">opendata.swiss</a> has the route geometry, and various pre-existing fields for the route length, maximum ascent, and so on, but there is no direct field that contains the route&#39;s minimum elevation, so it cannot be used directly in a filter.</p>

<p>Assuming that this is the sort of thing that must be both possible and straightforward, I <a href="https://mastodon.social/@nikclayton/116165150051259776" rel="nofollow">asked the QGIS community on the Fediverse</a>. <a href="https://fediscience.org/@tlohde" rel="nofollow"><a href="/@/tlohde@fediscience.org" class="u-url mention" rel="nofollow">@<span>tlohde@fediscience.org</span></a></a> was kind enough to <a href="https://fediscience.org/@tlohde/116166122556908448" rel="nofollow">reply</a>, and this post is adapted from their suggestions.</p>

<p>The rest of this post assumes you have already followed the steps in <a href="https://write.as/nikclayton/finding-showshoe-routes-using-swiss-opendata-and-qgis" rel="nofollow">Finding snowshoe routes using Swiss OpenData and QGIS</a>.</p>

<h2 id="outline" id="outline">Outline</h2>

<p>We are going to:</p>
<ol><li>Create a new column in the snowshoe data to contain the minimum elevation of each route.</li>
<li>Apply a QGIS function, <code>z_min</code>, to populate this column.</li>
<li>Update the existing filter to exclude routes with a minimum elevation below 1,500 metres.</li></ol>

<h2 id="creating-and-populating-the-column" id="creating-and-populating-the-column">Creating and populating the column</h2>
<ol><li>Open the “Field calculator” for the snowshoe attribute table.
<ol><li>Open the layer menu by right clicking the “schneeschuhwanderwege_2056.gpk” layer in the layer pane (bottom left)</li>
<li>From the menu click “Open Attribute Table” to open the attribute table pane below the map.</li>
<li>Open the “Field Calculator by clicking the “Edit” button and then the “Open field calculator” button in the toolbar above the attribute table
<img src="https://gist.github.com/user-attachments/assets/cbcadf66-88ea-4c5d-970b-b09d8bb92e3a" alt="open-attribute-table.png"/></li></ol></li>
<li>Create a new “min_elev” column in the data.
<ol><li>Ensure “Create a new field” is checked.</li>
<li>Enter “min_elev” in the “Output field name” field</li>
<li>Enter “<code>z_min($geometry)</code>” in the “Expression” field</li>
<li>Click “OK”
<img src="https://gist.github.com/user-attachments/assets/d89ecf63-658e-48f4-938f-1f43baba69c5" alt="field-calculator-min_elev.png"/></li></ol></li></ol>

<p>This has created a new column in the snow show data called “min_elev”, with a value calculated as the lowest Z point (elevation) in the route geometry for that row.</p>

<p>You can verify this in the attribute table. Scroll the table to the right and you will see the new <code>min_elev</code> column at the end.</p>

<h2 id="exclude-routes-below-1-500-metres" id="exclude-routes-below-1-500-metres">Exclude routes below 1,500 metres</h2>
<ol><li>Click the “Edit” button in the attribute pane to disable editing.</li>
<li>Open the layer menu by right clicking the “schneeschuhwanderwege_2056.gpk” layer in the layer pane.</li>
<li>Choose “Filter...” to open the Query Builder.</li>
<li>Click the “Test” button.
<ol><li>If you are using the query from yesterday you will see a dialog message, “The where clause returned 39 row(s)”. If you are using a different query the number of rows will be different.</li>
<li>Click OK to dismiss the dialog.</li></ol></li>
<li>Edit the query to add a final clause, <code>AND min_elev &gt;= 1500</code>. <img src="https://gist.github.com/user-attachments/assets/b6ddaa98-e355-4edc-bd8f-a6878879e0fc" alt="query-builder-min_elev.png"/></li>
<li>Click the “Test” button again.
<ol><li>If you where using the query from yesterday you will see a dialog message, “The where clause returned 9 row(s)”. So 30 routes that dip below 1,500 metres have been removed. If you were using a different query you will see a different number of results.</li>
<li>Click OK to dismiss the dialog.</li></ol></li>
<li>Click OK to dismiss the Query Builder</li></ol>
]]></content:encoded>
      <guid>https://nikclayton.writeas.com/using-qgis-to-filter-routes-by-minimum-elevation</guid>
      <pubDate>Wed, 04 Mar 2026 14:03:35 +0000</pubDate>
    </item>
    <item>
      <title>Finding showshoe routes using Swiss OpenData and QGIS</title>
      <link>https://nikclayton.writeas.com/finding-showshoe-routes-using-swiss-opendata-and-qgis?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Switzerland&#39;s great for winter activities, including snowshoeing. But finding somewhere to go can be frustrating.&#xA;&#xA;Sites like SchweizMobil have a list of routes and useful information; length, total ascent/descent, route maps, and so on. But support for searching for routes that meet specific critieria is lacking.&#xA;&#xA;In my case I wanted to find routes of between 5 and 12km, up to 300m of ascent, and taking no more than 4 hours. I&#39;d like to see this on a map (so I can get a rough idea of where in the country they are), and quickly click between them as part of making a decision.&#xA;&#xA;SchweizMobil doesn&#39;t support this sort of search, and you&#39;re left to scroll through routes, open them in different tabs, and eyeball some of the data to decide whether the route is suitable.&#xA;&#xA;There&#39;s a better way. opendata.swiss provides all the necessary data under a range of licenses.&#xA;&#xA;This data can be loaded in to QGIS, an open source desktop geographic information system (GIS) for displaying and manipulating map and related data.&#xA;&#xA;Together this allows you to create your own personalised map of suitable routes.&#xA;&#xA;At the end of this process you will be able to see a route on the map, including the elevation profile, like this:&#xA;&#xA;elevation-pane-active-profile.png&#xA;&#xA;Install and run QGIS&#xA;&#xA;Install QGIS by following the instructions at the download page at the QGIS Web Site.&#xA;&#xA;Launch QGIS after installation.&#xA;&#xA;Install QGIS plugins&#xA;&#xA;QGIS supports plugins that provide additional functionality, and we will use two:&#xA;&#xA;QuickMapServices&#xA;Swiss Geo Downloader&#xA;&#xA;Both of these plugins make it easy to load data from external sources directly into QGIS.&#xA;&#xA;QuickMapServices displays data from OpenStreetMap directly in QGIS. We will use this to provide the map of Switzerland and routing.&#xA;&#xA;Swiss Geo Downloader allows you to search for and import Swiss OpenData in QGIS.&#xA;&#xA;  There are other ways of accomplishing both of these tasks, the plugins make it straightforward.&#xA;&#xA;To install these plugins:&#xA;&#xA;From the QGIS menu choose &#34;Plugins   Manage and Install Plugins...&#34;.&#xA;Search for &#34;QuickMapServices&#34;, select it, and click &#34;Install Plugin&#34;.&#xA;Search for &#34;Swiss Geo Downloader&#34;, select it, and click &#34;Install Plugin&#34;.&#xA;The plugins dialog should look like this. The exact list of installed plugins may differ depending on the version of QGIS you have installed, but &#34;QuickMapServices&#34; and &#34;Swiss Geo Downloader&#34; should both be listed and checked.&#xA;plugins-dialog.png&#xA;Close the &#34;Plugins&#34; dialog.&#xA;&#xA;Use OpenStreetMap as the base layer&#xA;&#xA;From the QGIS menu choose &#34;Web   QuickMapServices   OSM   OSM Standard&#34;.&#xA;A world map should appear in QGIS, and the &#34;OSM Standard&#34; layer should appear in the &#34;Layers&#34; pane at the bottom left.&#xA;Zoom in on Switzerland. It should look like this: switzerland-base-layer.png&#xA;&#xA;Import snowshoe routes&#xA;&#xA;From the QGIS menu choose &#34;Plugins   Swiss Geo Downloader   Swiss Geo Downloader&#34;.&#xA;You may be prompted to switch to the Swiss coordinate reference system, LV95. Choose &#34;Yes&#34;.&#xA;&#x9;If you are not already zoomed in to Switzerland the map will become very distorted. This is normal. The distortion will disappear when you zoom in on Switzerland&#xA;A &#34;Swiss Geo Downloader&#34; window pane will open, with a search bar at the top.&#xA;Enter &#34;snowshoe&#34; in the search bar.&#xA;Choose the &#34;Snowshoe trails&#34; dataset from the results. Section 3 of the window should show &#34;schneeschuhwanderwege2056.gpkg&#34;&#xA;downloading-snowshoe-routes.png&#xA;Click &#34;Download&#34;, and choose a directory when prompted.&#xA;The &#34;schneeschuhwanderwege2056.gpkg&#34; layer should appear in the &#34;Layers&#34; pane downloaded-snowshoe-routes.png&#xA;&#xA;Improve visibility of the routes&#xA;&#xA;The snowshoe routes may be difficult to view on the map. To improve their visibility:&#xA;&#xA;Double-click the &#34;schneeschuhwanderwege2056.gpkg&#34; layer, to open the &#34;Layer Properties&#34; dialog.&#xA;Adjust the colour, width, and other properties. For example, click &#34;effect neon&#34; and set the width to &#34;1mm&#34; to quickly make the routes stand out.&#xA;layer-properties-symbology-neon.png&#xA;The available routes should now be much more visible on the map: layer-properties-neon-applied.png&#xA;&#xA;Filtering the routes&#xA;&#xA;The map is currently showing all ~ 200 routes. To filter them to your own criteria:&#xA;&#xA;Right click the &#34;schneeschuhwanderwege2056.gpkg&#34; layer and choose &#34;Filter...&#34; from the menu to open the &#34;Query Builder&#34; dialog.&#xA;Use this to build a query for the routes you care about.&#xA;&#xA;The query builder field names are in German, and have the following meanings:&#xA;&#xA;NameR: String, route name&#xA;NrR: Number, route number (e.g., 101 is SchweizMobil route 101)&#xA;BeschriebR: String, route display name&#xA;LaengeR: Number, length in kilometres, e.g., 8.1&#xA;HoeheAufR: Number, ascent in metres&#xA;HoeheAbR: Number, descent in metres&#xA;ZeitStZiR: Number, estimated time in minutes, e.g., 225 = 3h45m?&#xA;TechnikRen: String, difficulty level (english), e.g., &#34;blue&#34;&#xA;&#xA;For example, the following query filters to routes that are:&#xA;&#xA;Between 5km and 12km&#xA;Have a maximum ascent of 300m&#xA;Take 4 hours (4 * 60 = 240 minutes) or less&#xA;&#xA;LaengeR   = 5 AND LaengeR &lt;= 12 &#xA;AND HoeheAufR &lt;= 300&#xA;AND ZeitStZiR &lt;= 240&#xA;&#xA;query-builder.png&#xA;&#xA;After applying the filter the map will look like this (your map will look different if you used different filter criteria).&#xA;&#xA;filtered-routes.png&#xA;&#xA;View an elevation profile&#xA;&#xA;QGIS can display elevation profiles for routes.&#xA;&#xA;To activate this feature:&#xA;&#xA;Choose &#34;View   Elevation Profile&#34; from the menu.&#xA;The &#34;Elevation Profile&#34; pane will open at the bottom of the display. elevation-panel-after-open.png&#xA;Click the small &#34;Capture Curve from Feature&#34; button in the &#34;Elevation Profile&#34; pane. elevation-panel-capture-curve-from-feature.png&#xA;On the map, find the route you want to see the elevation profile for.&#xA;Click the route.&#xA;The elevation profile for the route will appear. elevation-pane-active-profile.png&#xA;&#xA;Click a route to open a web page&#xA;&#xA;The &#34;schneeschuhwanderwege2056.gpkg&#34; data also contains URLs for each route. QGIS can be configured to open that URL if you click the route.&#xA;&#xA;Right click the &#34;schneeschuhwanderwege2056.gpkg&#34; layer and choose &#34;Properties...&#34; from the menu to open the &#34;Layer Properties&#34; dialog.&#xA;Choose &#34;Actions&#34; from the list of properties on the left of the dialog.&#xA;Click the green &#34;+&#34; button to open the &#34;Add New Action&#34; dialog.&#xA;Use the following action settings:&#xA;&#x9;Type: &#34;Open URL&#34;&#xA;&#x9;Description: &#34;Open SchweizMobil&#34;&#xA;&#x9;Action Scopes: Check &#34;Canvas&#34;, leave other options unchecked&#xA;&#x9;Action Text: [% ChmURLen %]&#xA;&#x9;&#x9;This will open the English page. Other options are [% ChmURLde], [% ChmURLfr], [% ChmURLit], or [% ChmURLrm] for German, French, Italian, and Romansh respectively.&#xA;Click &#34;Ok&#34; twice to dismiss both dialogs.&#xA;&#xA;You can now enable the action in the QGIS toolbar.&#xA;&#xA;add-new-action-dialog.png&#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>Switzerland&#39;s great for winter activities, including snowshoeing. But finding somewhere to go can be frustrating.</p>

<p>Sites like <a href="https://schweizmobil.ch/en/snowshoe-trekking/local-routes" rel="nofollow">SchweizMobil</a> have a list of routes and useful information; length, total ascent/descent, route maps, and so on. But support for searching for routes that meet specific critieria is lacking.</p>

<p>In my case I wanted to find routes of between 5 and 12km, up to 300m of ascent, and taking no more than 4 hours. I&#39;d like to see this on a map (so I can get a rough idea of where in the country they are), and quickly click between them as part of making a decision.</p>

<p>SchweizMobil doesn&#39;t support this sort of search, and you&#39;re left to scroll through routes, open them in different tabs, and eyeball some of the data to decide whether the route is suitable.</p>

<p>There&#39;s a better way. <a href="https://www.opendata.swiss/en" rel="nofollow">opendata.swiss</a> provides all the necessary data under a <a href="https://opendata.swiss/en/terms-of-use" rel="nofollow">range of licenses</a>.</p>

<p>This data can be loaded in to <a href="https://www.qgis.org" rel="nofollow">QGIS</a>, an open source desktop <a href="https://en.wikipedia.org/wiki/Geographic_information_system" rel="nofollow">geographic information system (GIS)</a> for displaying and manipulating map and related data.</p>

<p>Together this allows you to create your own personalised map of suitable routes.</p>

<p>At the end of this process you will be able to see a route on the map, including the elevation profile, like this:</p>

<p><img src="https://gist.github.com/user-attachments/assets/05d78097-c18b-4625-87c9-a748fab8f79b" alt="elevation-pane-active-profile.png"/></p>

<h2 id="install-and-run-qgis" id="install-and-run-qgis">Install and run QGIS</h2>

<p>Install QGIS by following the instructions at the <a href="https://www.qgis.org/download/" rel="nofollow">download page at the QGIS Web Site</a>.</p>

<p>Launch QGIS after installation.</p>

<h2 id="install-qgis-plugins" id="install-qgis-plugins">Install QGIS plugins</h2>

<p>QGIS supports plugins that provide additional functionality, and we will use two:</p>
<ul><li>QuickMapServices</li>
<li>Swiss Geo Downloader</li></ul>

<p>Both of these plugins make it easy to load data from external sources directly into QGIS.</p>

<p>QuickMapServices displays data from OpenStreetMap directly in QGIS. We will use this to provide the map of Switzerland and routing.</p>

<p>Swiss Geo Downloader allows you to search for and import Swiss OpenData in QGIS.</p>

<blockquote><p>There are other ways of accomplishing both of these tasks, the plugins make it straightforward.</p></blockquote>

<p>To install these plugins:</p>
<ol><li>From the QGIS menu choose “Plugins &gt; Manage and Install Plugins...”.</li>
<li>Search for “QuickMapServices”, select it, and click “Install Plugin”.</li>
<li>Search for “Swiss Geo Downloader”, select it, and click “Install Plugin”.</li>
<li>The plugins dialog should look like this. The exact list of installed plugins may differ depending on the version of QGIS you have installed, but “QuickMapServices” and “Swiss Geo Downloader” should both be listed and checked.
<img src="https://gist.github.com/user-attachments/assets/09dbf1ad-7427-41e0-996d-1bf1dbfd3e81" alt="plugins-dialog.png"/></li>
<li>Close the “Plugins” dialog.</li></ol>

<h2 id="use-openstreetmap-as-the-base-layer" id="use-openstreetmap-as-the-base-layer">Use OpenStreetMap as the base layer</h2>
<ol><li>From the QGIS menu choose “Web &gt; QuickMapServices &gt; OSM &gt; OSM Standard”.</li>
<li>A world map should appear in QGIS, and the “OSM Standard” layer should appear in the “Layers” pane at the bottom left.</li>
<li>Zoom in on Switzerland. It should look like this: <img src="https://gist.github.com/user-attachments/assets/e2765d4d-32b1-4e2e-b36f-b77e35257823" alt="switzerland-base-layer.png"/></li></ol>

<h2 id="import-snowshoe-routes" id="import-snowshoe-routes">Import snowshoe routes</h2>
<ol><li>From the QGIS menu choose “Plugins &gt; Swiss Geo Downloader &gt; Swiss Geo Downloader”.</li>
<li>You may be prompted to switch to the Swiss coordinate reference system, LV95. Choose “Yes”.
<ol><li>If you are not already zoomed in to Switzerland the map will become very distorted. This is normal. The distortion will disappear when you zoom in on Switzerland</li></ol></li>
<li>A “Swiss Geo Downloader” window pane will open, with a search bar at the top.</li>
<li>Enter “snowshoe” in the search bar.</li>
<li>Choose the “Snowshoe trails” dataset from the results. Section 3 of the window should show “schneeschuhwanderwege_2056.gpkg”
<img src="https://gist.github.com/user-attachments/assets/df86aa32-9a05-47e3-9363-228cd4fc6b29" alt="downloading-snowshoe-routes.png"/></li>
<li>Click “Download”, and choose a directory when prompted.</li>
<li>The “schneeschuhwanderwege_2056.gpkg” layer should appear in the “Layers” pane <img src="https://gist.github.com/user-attachments/assets/b77a3416-7623-40f7-b6fe-4aa83272c93c" alt="downloaded-snowshoe-routes.png"/></li></ol>

<h2 id="improve-visibility-of-the-routes" id="improve-visibility-of-the-routes">Improve visibility of the routes</h2>

<p>The snowshoe routes may be difficult to view on the map. To improve their visibility:</p>
<ol><li>Double-click the “schneeschuhwanderwege_2056.gpkg” layer, to open the “Layer Properties” dialog.</li>
<li>Adjust the colour, width, and other properties. For example, click “effect neon” and set the width to “1mm” to quickly make the routes stand out.
<img src="https://gist.github.com/user-attachments/assets/cb03658f-ea60-42d3-95cb-c48f356ae070" alt="layer-properties-symbology-neon.png"/></li>
<li>The available routes should now be much more visible on the map: <img src="https://gist.github.com/user-attachments/assets/7f14c623-71f5-44cb-a71f-8415f66e6754" alt="layer-properties-neon-applied.png"/></li></ol>

<h2 id="filtering-the-routes" id="filtering-the-routes">Filtering the routes</h2>

<p>The map is currently showing all ~ 200 routes. To filter them to your own criteria:</p>
<ol><li>Right click the “schneeschuhwanderwege_2056.gpkg” layer and choose “Filter...” from the menu to open the “Query Builder” dialog.</li>
<li>Use this to build a query for the routes you care about.</li></ol>

<p>The query builder field names are in German, and have the following meanings:</p>
<ul><li>NameR: String, route name</li>
<li>NrR: Number, route number (e.g., 101 is SchweizMobil route 101)</li>
<li>BeschriebR: String, route display name</li>
<li>LaengeR: Number, length in kilometres, e.g., 8.1</li>
<li>HoeheAufR: Number, ascent in metres</li>
<li>HoeheAbR: Number, descent in metres</li>
<li>ZeitStZiR: Number, estimated time in minutes, e.g., 225 = 3h45m?</li>
<li>TechnikR_en: String, difficulty level (english), e.g., “blue”</li></ul>

<p>For example, the following query filters to routes that are:</p>
<ol><li>Between 5km and 12km</li>
<li>Have a maximum ascent of 300m</li>
<li>Take 4 hours (4 * 60 = 240 minutes) or less</li></ol>

<pre><code>LaengeR &gt;= 5 AND LaengeR &lt;= 12 
AND HoeheAufR &lt;= 300
AND ZeitStZiR &lt;= 240
</code></pre>

<p><img src="https://gist.github.com/user-attachments/assets/3b5e589f-73ef-42ec-ab01-d39476ec3fd4" alt="query-builder.png"/></p>

<p>After applying the filter the map will look like this (your map will look different if you used different filter criteria).</p>

<p><img src="https://gist.github.com/user-attachments/assets/58ac5bdc-7873-42e7-8132-b9e6df9c6241" alt="filtered-routes.png"/></p>

<h2 id="view-an-elevation-profile" id="view-an-elevation-profile">View an elevation profile</h2>

<p>QGIS can display elevation profiles for routes.</p>

<p>To activate this feature:</p>
<ol><li>Choose “View &gt; Elevation Profile” from the menu.</li>
<li>The “Elevation Profile” pane will open at the bottom of the display. <img src="https://gist.github.com/user-attachments/assets/65df2db1-1368-4544-9d2e-1744c63072c1" alt="elevation-panel-after-open.png"/></li>
<li>Click the small “Capture Curve from Feature” button in the “Elevation Profile” pane. <img src="https://gist.github.com/user-attachments/assets/442eedbb-627f-4acc-94d5-4e3a271d668f" alt="elevation-panel-capture-curve-from-feature.png"/></li>
<li>On the map, find the route you want to see the elevation profile for.</li>
<li>Click the route.</li>
<li>The elevation profile for the route will appear. <img src="https://gist.github.com/user-attachments/assets/05d78097-c18b-4625-87c9-a748fab8f79b" alt="elevation-pane-active-profile.png"/></li></ol>

<h2 id="click-a-route-to-open-a-web-page" id="click-a-route-to-open-a-web-page">Click a route to open a web page</h2>

<p>The “schneeschuhwanderwege_2056.gpkg” data also contains URLs for each route. QGIS can be configured to open that URL if you click the route.</p>
<ol><li>Right click the “schneeschuhwanderwege_2056.gpkg” layer and choose “Properties...” from the menu to open the “Layer Properties” dialog.</li>
<li>Choose “Actions” from the list of properties on the left of the dialog.</li>
<li>Click the green “+” button to open the “Add New Action” dialog.</li>
<li>Use the following action settings:
<ol><li>Type: “Open URL”</li>
<li>Description: “Open SchweizMobil”</li>
<li>Action Scopes: Check “Canvas”, leave other options unchecked</li>
<li>Action Text: <code>[% ChmURL_en %]</code>
<ol><li>This will open the English page. Other options are <code>[% ChmURL_de]</code>, <code>[% ChmURL_fr]</code>, <code>[% ChmURL_it]</code>, or <code>[% ChmURL_rm]</code> for German, French, Italian, and Romansh respectively.</li></ol></li></ol></li>
<li>Click “Ok” twice to dismiss both dialogs.</li></ol>

<p>You can now enable the action in the QGIS toolbar.</p>

<p><img src="https://gist.github.com/user-attachments/assets/2c9ab215-e30d-468d-8714-de4fd614e37f" alt="add-new-action-dialog.png"/></p>
]]></content:encoded>
      <guid>https://nikclayton.writeas.com/finding-showshoe-routes-using-swiss-opendata-and-qgis</guid>
      <pubDate>Tue, 03 Mar 2026 08:51:32 +0000</pubDate>
    </item>
    <item>
      <title>One writing tip</title>
      <link>https://nikclayton.writeas.com/one-writing-tip?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Suppose you have to write some documentation. It might be a tutorial, a how-to guide, or an explanation of a topic (see Diátaxis for more on those).&#xA;&#xA;Challenges when doing this include:&#xA;&#xA;Deciding how to structure the document.&#xA;Deciding when the document is complete.&#xA;Over-stuffing the document with information that is not relevant to the reader at that time.&#xA;Ensuring the reader has the necessary prerequisite knowledge to understand the material.&#xA;&#xA;To combat those problems start the document with a &#34;Synopsis&#34; section that consists of:&#xA;&#xA;1-n paragraphs that provide a very brief introduction to the topic. That might be an overview of the topic, or perhaps a description of the specific problem the documentation will help you solve.&#xA;A list of 0-n bullet points that start &#34;Before reading this document you should:&#34;.&#xA;&#x9;Each bullet point should list a task to complete, with a link to material that explains how the reader can complete the task. The task might be an activity they need to complete, or a document they should read before this one.&#xA;A list of 1-n bullet points that start &#34;After reading this document you will know:&#34;&#xA;&#xA;I have found this to be invaluable when organising your thoughts.&#xA;&#xA;If you cannot write a brief introduction to the topic that is an indication you either do not understand it well enough to write about it, or the topic is too complex to cover in a single document and should be separated into smaller documents.&#xA;The &#34;... you will know&#34; bullet points serve several functions:&#xA;&#x9;They&#39;re your &#34;to-do list&#34; of things to write about in the document. You know the document is complete / ready for editing when you have ticked off each bullet point.&#xA;&#x9;If you find yourself writing more than ~ seven bullet points that&#39;s a good sign the document is going to be too complex, and should be broken in to smaller documents.&#xA;Similarly, the &#34;... you should:&#34; bullet points have several functions:&#xA;&#x9;They allow you to be explicit about what is not covered in the document.&#xA;&#x9;They clearly direct the reader to the other material.&#xA;&#x9;They highlight material that may be missing. If you find yourself writing an entry in this section but do not have documentation that tells the user how to complete this task you have discovered another document you need to write.&#xA;&#xA;This works whether you are writing a stand-alone document or one that is part of a collection.&#xA;&#xA;I first adopted this technique when I was co-editing the 2nd edition of the FreeBSD Handbook, and although that is long in the past, today&#39;s handbook continues the tradition.&#xA;&#xA;The synopsis for the &#34;Wayland&#34; chapter is a good example. It starts:&#xA;&#xA;  An installation of FreeBSD using bsdinstall does not automatically install a graphical user interface. This chapter describes how to select, install, and configure a Wayland compositor, which provides a graphical environment.&#xA;    Before reading this chapter, you should know:&#xA;    - How to install additional third-party software.&#xA;  - How to identify and configure drivers for your graphics hardware.&#xA;    After reading this chapter, you will know:&#xA;    - How to configure FreeBSD to host a Wayland graphical environment.&#xA;  - How to install and configure a Wayland compositor.&#xA;  - How to run programs designed for the older X Window System.&#xA;  - How to configure remote desktop access to a Wayland graphical environment.&#xA;&#xA;In that example:&#xA;&#xA;The introductory paragraph provides context for the reader.&#xA;The &#34;... you should know:&#34; bullets clearly explain prerequisite knowledge, and direct the reader to the right place to learn that knowledge.&#xA;The &#34;... you will know:&#34; bullets tightly scope the content of the document, and allow the reader to rapidly determine whether this document is going to be helpful for whatever task they are carrying out.&#xA;&#xA;---&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>Suppose you have to write some documentation. It might be a tutorial, a how-to guide, or an explanation of a topic (see <a href="https://diataxis.fr/" rel="nofollow">Diátaxis</a> for more on those).</p>

<p>Challenges when doing this include:</p>
<ul><li>Deciding how to structure the document.</li>
<li>Deciding when the document is complete.</li>
<li>Over-stuffing the document with information that is not relevant to the reader at that time.</li>
<li>Ensuring the reader has the necessary prerequisite knowledge to understand the material.</li></ul>

<p>To combat those problems start the document with a “Synopsis” section that consists of:</p>
<ul><li>1-n paragraphs that provide a very brief introduction to the topic. That might be an overview of the topic, or perhaps a description of the specific problem the documentation will help you solve.</li>
<li>A list of 0-n bullet points that start “Before reading this document you should:“.
<ul><li>Each bullet point should list a task to complete, with a link to material that explains how the reader can complete the task. The task might be an activity they need to complete, or a document they should read before this one.</li></ul></li>
<li>A list of 1-n bullet points that start “After reading this document you will know:”</li></ul>

<p>I have found this to be invaluable when organising your thoughts.</p>
<ol><li>If you cannot write a brief introduction to the topic that is an indication you either do not understand it well enough to write about it, or the topic is too complex to cover in a single document and should be separated into smaller documents.</li>
<li>The “... you will know” bullet points serve several functions:
<ol><li>They&#39;re your “to-do list” of things to write about in the document. You know the document is complete / ready for editing when you have ticked off each bullet point.</li>
<li>If you find yourself writing more than ~ seven bullet points that&#39;s a good sign the document is going to be too complex, and should be broken in to smaller documents.</li></ol></li>
<li>Similarly, the “... you should:” bullet points have several functions:
<ol><li>They allow you to be explicit about what is not covered in the document.</li>
<li>They clearly direct the reader to the other material.</li>
<li>They highlight material that may be missing. If you find yourself writing an entry in this section but do not have documentation that tells the user how to complete this task you have discovered another document you need to write.</li></ol></li></ol>

<p>This works whether you are writing a stand-alone document or one that is part of a collection.</p>

<p>I first adopted this technique when I was co-editing the 2nd edition of the <a href="https://docs.freebsd.org/en/books/handbook/" rel="nofollow">FreeBSD Handbook</a>, and although that is long in the past, today&#39;s handbook continues the tradition.</p>

<p>The synopsis for the “<a href="https://docs.freebsd.org/en/books/handbook/wayland/" rel="nofollow">Wayland</a>” chapter is a good example. It starts:</p>

<blockquote><p>An installation of FreeBSD using bsdinstall does not automatically install a graphical user interface. This chapter describes how to select, install, and configure a Wayland compositor, which provides a graphical environment.</p>

<p>Before reading this chapter, you should know:</p>
<ul><li>How to install <a href="https://docs.freebsd.org/en/books/handbook/ports/#ports" rel="nofollow">additional third-party software</a>.</li>
<li>How to identify and configure <a href="https://docs.freebsd.org/en/books/handbook/x11/#x-graphic-card-drivers" rel="nofollow">drivers for your graphics hardware</a>.</li></ul>

<p>After reading this chapter, you will know:</p>
<ul><li>How to configure FreeBSD to host a Wayland graphical environment.</li>
<li>How to install and configure a Wayland compositor.</li>
<li>How to run programs designed for the older X Window System.</li>
<li>How to configure remote desktop access to a Wayland graphical environment.</li></ul>
</blockquote>

<p>In that example:</p>
<ul><li>The introductory paragraph provides context for the reader.</li>
<li>The “... you should know:” bullets clearly explain prerequisite knowledge, and direct the reader to the right place to learn that knowledge.</li>
<li>The “... you will know:” bullets tightly scope the content of the document, and allow the reader to rapidly determine whether this document is going to be helpful for whatever task they are carrying out.</li></ul>

<hr/>
]]></content:encoded>
      <guid>https://nikclayton.writeas.com/one-writing-tip</guid>
      <pubDate>Fri, 06 Dec 2024 11:57:29 +0000</pubDate>
    </item>
    <item>
      <title>Validating and parsing</title>
      <link>https://nikclayton.writeas.com/validating-and-parsing?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[  Inspired by a discussion in the joinmastodon.org Discord.&#xA;&#xA;Someone&#39;s writing an app processing incoming HTTP requests with a Content-Type header. Specifically, they want to handle the case where the content type is application/json. &#xA;&#xA;They noticed some clients are sending an unnecessary charset=utf-8 parameter in the content type, and wondered how they should properly handle this parameter.&#xA;&#xA;They&#39;re doing this as a learning exercise so wanted to avoid leaning on an existing library if possible.&#xA;&#xA;The discussion went back and forth a little bit between validation and parsing without really getting in to the meat of it, it&#39;s too long for a chat message post, and I&#39;m not aware of a good discussion of the topic elsewhere, hence this post.&#xA;&#xA;What to do?&#xA;&#xA;The difference between validation and parsing&#xA;&#xA;I use the terms to mean the following.&#xA;&#xA;You validate incoming data to decide if your code should continue on the happy path, or branch to an error handler because the data is invalid. The incoming data will not be used again.&#xA;&#xA;You parse incoming data to validate it, and to extract the information to a different type for use elsewhere in the program.&#xA;&#xA;To use Pachli as an example, the code validates the content type of incoming data as application/json because if it&#39;s not then an error has occurred. The content type is not used after that.&#xA;&#xA;Pachli parses a server&#39;s version string to a dedicated Version type to hold a semantic version because the version information is used elsewhere in the code to make decisions. &#xA;&#xA;Parsing to the dedicated type once means the rest of the code knows the version is valid and can be reasoned about, instead of repeatedly having to re-parse the version string.&#xA;The Content-Type header&#xA;&#xA;The Content-Type header specification is defined in RFC 9110 sect. 8.3. Using ABNF the grammar for the header is&#xA;&#xA;token          = 1tchar&#xA;&#xA;tchar          = &#34;!&#34; / &#34;#&#34; / &#34;$&#34; / &#34;%&#34; / &#34;&amp;&#34; / &#34;&#39;&#34; / &#34;&#34;&#xA;                 / &#34;+&#34; / &#34;-&#34; / &#34;.&#34; / &#34;^&#34; / &#34;&#34; / &#34;`&#34; / &#34;|&#34; / &#34;~&#34;&#xA;                 / DIGIT / ALPHA&#xA;                 ; any VCHAR, except delimiters&#xA;&#xA;parameters      = ( OWS &#34;;&#34; OWS [ parameter ] )&#xA;parameter       = parameter-name &#34;=&#34; parameter-value&#xA;parameter-name  = token&#xA;parameter-value = ( token / quoted-string )&#xA;  &#xA;media-type = type &#34;/&#34; subtype parameters&#xA;type       = token&#xA;subtype    = tokenContent-Type = media-type&#xA;&#xA;Content-Type = media-type&#xA;&#xA;It also notes&#xA;&#xA;  The type and subtype tokens are case-insensitive.&#xA;&#xA;and gives these examples&#xA;&#xA;text/html;charset=utf-8&#xA;Text/HTML;Charset=&#34;utf-8&#34;&#xA;text/html; charset=&#34;utf-8&#34;&#xA;text/html;charset=UTF-8&#xA;&#xA;RFC 8259 defines the application/json media type, and is explicit that this type does not have a charset parameter, writing:&#xA;&#xA;  Note:  No &#34;charset&#34; parameter is defined for this registration. Adding one really has no effect on compliant recipients.&#xA;&#xA;What to do?&#xA;&#xA;The original questioner can now decide whether they want to validate the header as application/json, or parse the header to a more specific set of types.&#xA;&#xA;Validation&#xA;&#xA;From the definition of the Content-Type header and the application/json media type we can see a sensible strategy for validation would be:&#xA;&#xA;Remove everything from the header value after-and-including the first occurrence of ;&#xA;Trim any whitespace from the start and end of the string&#xA;Perform a case-insensitive comparison of the value with application/json&#xA;&#xA;Step 1 handles malformed clients or servers that emit variations of application/json;charset=utf-8 (or any other charset). While technically not correct this is unlikely to impede interoperability.&#xA;&#xA;Step 2 is also for malformed clients or servers. The specification does not allow spaces before the primary type (application), and there may be spaces between the subtype and the ; that was removed in step 1. Again, removing these should be harmless and improves interoperability.&#xA;&#xA;Step 3 validates the header contains the correct value.&#xA;&#xA;Parsing&#xA;&#xA;Parsing the header is appropriate if the application is going to branch based on the type and subtype. For example, different handlers for application/json and application/activity+json.&#xA;&#xA;To do that I would create specific Python types to represent the parameters and types that can appear in a Content-Type header, and have a function that parses the header and returns one of those types.&#xA;&#xA;The types should include an explicit Unknown value to indicate an unhandled type, and can either raise errors or return an additional error type.&#xA;&#xA;For example:&#xA;&#xA;import re&#xA;from dataclasses import dataclass&#xA;&#xA;This is an example to demonstrate parsing a value to one of a&#xA;specific set of types, distinct from simply validating the value&#xA;matches expectations.&#xA;&#xA;@dataclass&#xA;class BaseParameter:&#xA;    &#34;&#34;&#34;&#xA;    Base class for all parameters.&#xA;&#xA;    value: Value of the parameter as it appeared in the header.&#xA;    &#34;&#34;&#34;&#xA;    value: str&#xA;&#xA;@dataclass&#xA;class Charset(BaseParameter):&#xA;    &#34;&#34;&#34;A &#39;charset=...&#39; parameter.&#34;&#34;&#34;&#xA;    pass&#xA;&#xA;@dataclass&#xA;class UnknownParameter(BaseParameter):&#xA;    &#34;&#34;&#34;&#xA;    An unknown parameter.&#xA;    &#xA;    name: Parsed name of the parameter&#xA;    value: Parsed value of the parameter&#xA;    original: Original parameter string as it appeared in the header.&#xA;    &#34;&#34;&#34;&#xA;    name: str&#xA;    original: str&#xA;&#xA;Parameter = Charset | UnknownParameter&#xA;&#34;&#34;&#34;Parameters that can occur in a content-type header.&#34;&#34;&#34;&#xA;&#xA;@dataclass&#xA;class ApplicationJson:&#xA;    &#34;&#34;&#34;The application/json content type.&#34;&#34;&#34;&#xA;    pass&#xA;&#xA;@dataclass&#xA;class ApplicationActivityPlusJson:&#xA;    &#34;&#34;&#34;&#xA;    The application/activity+json content type&#xA;&#xA;    charset: Parsed value of the &#39;charset&#39; parameter, if present.&#xA;    &#34;&#34;&#34;&#xA;    charset: Charset | None&#xA;&#xA;@dataclass&#xA;class UnknownContentType:&#xA;    &#34;&#34;&#34;&#xA;    An unknown content type.&#xA;&#xA;    type: Parsed name of the type&#xA;    parameters: Parsed list of parameters, if present.&#xA;    original: Original content type as it appeared in the header.&#xA;    &#34;&#34;&#34;&#xA;    type: str&#xA;    parameters: list[Parameter]&#xA;    original: str&#xA;&#xA;ContentType = ApplicationJson | ApplicationActivityPlusJson | UnknownContentType&#xA;&#34;&#34;&#34;Possible content type values.&#34;&#34;&#34;&#xA;&#xA;THIS IS NOT A PRODUCTION QUALITY PARSER&#xA;def parsecontenttype(val: str) -  ContentType:&#xA;    r = re.compile(&#39;^(?Ptype+)(?:;(?Pparameters.))?&#39;)&#xA;    m = r.search(val)&#xA;    if m is None:&#xA;        raise ValueError&#xA;    type = m.group(&#39;type&#39;)&#xA;    if type is not None:&#xA;        type = type.lower().strip()&#xA;    match type:&#xA;        case &#39;application/json&#39;:&#xA;            return ApplicationJson()&#xA;        case &#39;application/activity+json&#39;:&#xA;            parameters = parseparameters(m.group(&#39;parameters&#39;))&#xA;            charset = (e for e in parameters if isinstance(e, Charset)&#xA;                       or [None])[0]&#xA;            return ApplicationActivityPlusJson(charset)&#xA;        case :&#xA;            parameters = parseparameters(m.group(&#39;parameters&#39;))&#xA;            return UnknownContentType(type, parameters, val)&#xA;&#xA;THIS IS NOT A PRODUCTION QUALITY PARSER&#xA;def parseparameters(val: str) -  list[Parameter]:&#xA;    if val is None:&#xA;        return []&#xA;&#xA;    parameterstrs = val.split(&#39;;&#39;)&#xA;    r = []&#xA;    for parameterstr in parameterstrs:&#xA;        parameterstr = parameterstr.strip()&#xA;        (name, value) = re.split(r&#39;\s=\s&#39;, parameterstr, maxsplit=1)&#xA;        match name.lower():&#xA;            case &#39;charset&#39;:&#xA;                r.append(Charset(value.lower()))&#xA;            case :&#xA;                r.append(UnknownParameter(name, value, parameterstr))&#xA;    return r&#xA;&#xA;if name == &#34;main&#34;:&#xA;    print(parsecontenttype(&#39;application/json&#39;))&#xA;    print(parsecontenttype(&#39;application/JSON&#39;))&#xA;    print(parsecontenttype(&#39;  application/json  &#39;))&#xA;    print(parsecontenttype(&#39;application/json ; charset=utf-8&#39;))&#xA;    print(parsecontenttype(&#39;application/activity+json&#39;))&#xA;    print(parsecontenttype(&#39;application/activity+json;charset=us-ascii&#39;))&#xA;    print(parsecontenttype(&#39;made/up; charset=utf-8; some=parameter&#39;))&#xA;&#xA;    match parsecontent_type(&#39;application/activity+json;charset=us-ascii&#39;):&#xA;        case ApplicationJson():&#xA;            print(&#39;It was some form of application/json&#39;)&#xA;        case ApplicationActivityPlusJson(charset):&#xA;            print(&#39;It was some form of application/activity+json&#39;)&#xA;            if charset is not None:&#xA;                print(f&#39;Charset was {charset.value}&#39;)&#xA;        case UnknownContentType(type, parameters, original):&#xA;            print(f&#39;Content type &#34;{original}&#34; was not recognised&#39;)&#xA;Anything else?&#xA;&#xA;Additional checks could be performed.&#xA;&#xA;Instead of ignoring the charset parameter, parse the value and confirm it is utf-8. If it is not then signal the error in some fashion so the operator of the offending client/server can be informed. For example, receiving application/json;charset=us-ascii should be a red flag somewhere.]]&gt;</description>
      <content:encoded><![CDATA[<blockquote><p>Inspired by a discussion in the joinmastodon.org Discord.</p></blockquote>

<p>Someone&#39;s writing an app processing incoming HTTP requests with a <code>Content-Type</code> header. Specifically, they want to handle the case where the content type is <code>application/json</code>.</p>

<p>They noticed some clients are sending an unnecessary <code>charset=utf-8</code> parameter in the content type, and wondered how they should properly handle this parameter.</p>

<p>They&#39;re doing this as a learning exercise so wanted to avoid leaning on an existing library if possible.</p>

<p>The discussion went back and forth a little bit between validation and parsing without really getting in to the meat of it, it&#39;s too long for a chat message post, and I&#39;m not aware of a good discussion of the topic elsewhere, hence this post.</p>

<p>What to do?</p>

<h2 id="the-difference-between-validation-and-parsing" id="the-difference-between-validation-and-parsing">The difference between validation and parsing</h2>

<p>I use the terms to mean the following.</p>

<p>You <strong>validate</strong> incoming data to decide if your code should continue on the happy path, or branch to an error handler because the data is invalid. The incoming data will not be used again.</p>

<p>You <strong>parse</strong> incoming data to validate it, <strong>and</strong> to extract the information to a different type for use elsewhere in the program.</p>

<p>To use <a href="https://pachli.app" rel="nofollow">Pachli</a> as an example, the code <strong>validates</strong> the content type of incoming data as <code>application/json</code> because if it&#39;s not then an error has occurred. The content type is not used after that.</p>

<p>Pachli <strong>parses</strong> a server&#39;s version string to a <a href="https://github.com/z4kn4fein/kotlin-semver" rel="nofollow">dedicated Version type</a> to hold a <a href="https://semver.org" rel="nofollow">semantic version</a> because the version information is used elsewhere in the code to make decisions.</p>

<p>Parsing to the dedicated type <strong>once</strong> means the rest of the code knows the version is valid and can be reasoned about, instead of repeatedly having to re-parse the version string.</p>

<h2 id="the-content-type-header" id="the-content-type-header">The Content-Type header</h2>

<p>The <code>Content-Type</code> header specification is defined in <a href="https://www.rfc-editor.org/rfc/rfc9110#section-8.3" rel="nofollow">RFC 9110 sect. 8.3</a>. Using <a href="https://www.rfc-editor.org/info/rfc5234" rel="nofollow">ABNF</a> the grammar for the header is</p>

<pre><code>token          = 1*tchar

tchar          = &#34;!&#34; / &#34;#&#34; / &#34;$&#34; / &#34;%&#34; / &#34;&amp;&#34; / &#34;&#39;&#34; / &#34;*&#34;
                 / &#34;+&#34; / &#34;-&#34; / &#34;.&#34; / &#34;^&#34; / &#34;_&#34; / &#34;`&#34; / &#34;|&#34; / &#34;~&#34;
                 / DIGIT / ALPHA
                 ; any VCHAR, except delimiters

parameters      = *( OWS &#34;;&#34; OWS [ parameter ] )
parameter       = parameter-name &#34;=&#34; parameter-value
parameter-name  = token
parameter-value = ( token / quoted-string )
  
media-type = type &#34;/&#34; subtype parameters
type       = token
subtype    = tokenContent-Type = media-type

Content-Type = media-type
</code></pre>

<p>It also notes</p>

<blockquote><p>The type and subtype tokens are case-insensitive.</p></blockquote>

<p>and gives these examples</p>

<pre><code>text/html;charset=utf-8
Text/HTML;Charset=&#34;utf-8&#34;
text/html; charset=&#34;utf-8&#34;
text/html;charset=UTF-8
</code></pre>

<p><a href="https://datatracker.ietf.org/doc/html/rfc8259" rel="nofollow">RFC 8259</a> defines the <code>application/json</code> media type, and is explicit that this type does not have a <code>charset</code> parameter, writing:</p>

<blockquote><p>   Note:  No “charset” parameter is defined for this registration. Adding one really has no effect on compliant recipients.</p></blockquote>

<h2 id="what-to-do" id="what-to-do">What to do?</h2>

<p>The original questioner can now decide whether they want to validate the header as <code>application/json</code>, or parse the header to a more specific set of types.</p>

<h3 id="validation" id="validation">Validation</h3>

<p>From the definition of the <code>Content-Type</code> header and the <code>application/json</code> media type we can see a sensible strategy for <em>validation</em> would be:</p>
<ol><li>Remove everything from the header value after-and-including the first occurrence of <code>;</code></li>
<li>Trim any whitespace from the start and end of the string</li>
<li>Perform a case-insensitive comparison of the value with <code>application/json</code></li></ol>

<p>Step 1 handles malformed clients or servers that emit variations of <code>application/json;charset=utf-8</code> (or any other charset). While technically not correct this is unlikely to impede interoperability.</p>

<p>Step 2 is also for malformed clients or servers. The specification does not allow spaces before the primary type (<code>application</code>), and there may be spaces between the subtype and the <code>;</code> that was removed in step 1. Again, removing these should be harmless and improves interoperability.</p>

<p>Step 3 validates the header contains the correct value.</p>

<h3 id="parsing" id="parsing">Parsing</h3>

<p>Parsing the header is appropriate if the application is going to branch based on the type and subtype. For example, different handlers for <code>application/json</code> and <code>application/activity+json</code>.</p>

<p>To do that I would create specific Python types to represent the parameters and types that can appear in a <code>Content-Type</code> header, and have a function that parses the header and returns one of those types.</p>

<p>The types should include an explicit <code>Unknown</code> value to indicate an unhandled type, and can either raise errors or return an additional error type.</p>

<p>For example:</p>

<pre><code class="language-python">import re
from dataclasses import dataclass

# This is an example to demonstrate parsing a value to one of a
# specific set of types, distinct from simply validating the value
# matches expectations.


@dataclass
class BaseParameter:
    &#34;&#34;&#34;
    Base class for all parameters.

    value: Value of the parameter as it appeared in the header.
    &#34;&#34;&#34;
    value: str


@dataclass
class Charset(BaseParameter):
    &#34;&#34;&#34;A &#39;charset=...&#39; parameter.&#34;&#34;&#34;
    pass


@dataclass
class UnknownParameter(BaseParameter):
    &#34;&#34;&#34;
    An unknown parameter.
    
    name: Parsed name of the parameter
    value: Parsed value of the parameter
    original: Original parameter string as it appeared in the header.
    &#34;&#34;&#34;
    name: str
    original: str


Parameter = Charset | UnknownParameter
&#34;&#34;&#34;Parameters that can occur in a content-type header.&#34;&#34;&#34;


@dataclass
class ApplicationJson:
    &#34;&#34;&#34;The application/json content type.&#34;&#34;&#34;
    pass


@dataclass
class ApplicationActivityPlusJson:
    &#34;&#34;&#34;
    The application/activity+json content type

    charset: Parsed value of the &#39;charset&#39; parameter, if present.
    &#34;&#34;&#34;
    charset: Charset | None


@dataclass
class UnknownContentType:
    &#34;&#34;&#34;
    An unknown content type.

    type: Parsed name of the type
    parameters: Parsed list of parameters, if present.
    original: Original content type as it appeared in the header.
    &#34;&#34;&#34;
    type: str
    parameters: list[Parameter]
    original: str


ContentType = ApplicationJson | ApplicationActivityPlusJson | UnknownContentType
&#34;&#34;&#34;Possible content type values.&#34;&#34;&#34;


# THIS IS NOT A PRODUCTION QUALITY PARSER
def parse_content_type(val: str) -&gt; ContentType:
    r = re.compile(&#39;^(?P&lt;type&gt;[^;]+)(?:;(?P&lt;parameters&gt;.*))?&#39;)
    m = r.search(val)
    if m is None:
        raise ValueError
    type = m.group(&#39;type&#39;)
    if type is not None:
        type = type.lower().strip()
    match type:
        case &#39;application/json&#39;:
            return ApplicationJson()
        case &#39;application/activity+json&#39;:
            parameters = parse_parameters(m.group(&#39;parameters&#39;))
            charset = ([e for e in parameters if isinstance(e, Charset)][:1]
                       or [None])[0]
            return ApplicationActivityPlusJson(charset)
        case _:
            parameters = parse_parameters(m.group(&#39;parameters&#39;))
            return UnknownContentType(type, parameters, val)


# THIS IS NOT A PRODUCTION QUALITY PARSER
def parse_parameters(val: str) -&gt; list[Parameter]:
    if val is None:
        return []

    parameter_strs = val.split(&#39;;&#39;)
    r = []
    for parameter_str in parameter_strs:
        parameter_str = parameter_str.strip()
        (name, value) = re.split(r&#39;\s*=\s*&#39;, parameter_str, maxsplit=1)
        match name.lower():
            case &#39;charset&#39;:
                r.append(Charset(value.lower()))
            case _:
                r.append(UnknownParameter(name, value, parameter_str))
    return r


if __name__ == &#34;__main__&#34;:
    print(parse_content_type(&#39;application/json&#39;))
    print(parse_content_type(&#39;application/JSON&#39;))
    print(parse_content_type(&#39;  application/json  &#39;))
    print(parse_content_type(&#39;application/json ; charset=utf-8&#39;))
    print(parse_content_type(&#39;application/activity+json&#39;))
    print(parse_content_type(&#39;application/activity+json;charset=us-ascii&#39;))
    print(parse_content_type(&#39;made/up; charset=utf-8; some=parameter&#39;))

    match parse_content_type(&#39;application/activity+json;charset=us-ascii&#39;):
        case ApplicationJson():
            print(&#39;It was some form of application/json&#39;)
        case ApplicationActivityPlusJson(charset):
            print(&#39;It was some form of application/activity+json&#39;)
            if charset is not None:
                print(f&#39;Charset was {charset.value}&#39;)
        case UnknownContentType(type, parameters, original):
            print(f&#39;Content type &#34;{original}&#34; was not recognised&#39;)
</code></pre>

<h2 id="anything-else" id="anything-else">Anything else?</h2>

<p>Additional checks could be performed.</p>
<ul><li>Instead of ignoring the <code>charset</code> parameter, parse the value and confirm it is <code>utf-8</code>. If it is not then signal the error in some fashion so the operator of the offending client/server can be informed. For example, receiving <code>application/json;charset=us-ascii</code> should be a red flag somewhere.</li></ul>
]]></content:encoded>
      <guid>https://nikclayton.writeas.com/validating-and-parsing</guid>
      <pubDate>Sat, 20 Jul 2024 11:51:35 +0000</pubDate>
    </item>
    <item>
      <title>Pachli</title>
      <link>https://nikclayton.writeas.com/pachli?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[After recent events and looking at the existing open source Android Mastodon clients I decided there&#39;s space for one more, with a specific focus.&#xA;&#xA;Pachli (website, google play, f-droid, github, mastodon)&#xA;&#xA;To quote from https://pachli.app/pachli/2023/09/06/hello-pachli.html:&#xA;&#xA;Pachli is an application (now) and an association (aspirational).&#xA;&#xA;Pachli-the-application is a best-in-class open source Android application for Mastodon and Mastodon-like servers. If you’re familiar with Tusky then you’ll love Pachli.&#xA;&#xA;Pachli-the-association is intended to provide a first class organisation to manage the development of the application under the 7 cooperative principles:&#xA;&#xA;Voluntary and open membership&#xA;Democratic member control&#xA;Member economic participation&#xA;Autonomy and independence&#xA;Education, Training, and Information&#xA;Cooperation among Cooperatives&#xA;Concern for Community&#xA;&#xA;The application is a rapidly iterating fork of the popular Tusky Mastodon client, branched from version 23.0 of that application.&#xA;&#xA;Pachli includes many changes from Tusky 23.0, including:&#xA;&#xA;New features&#xA;&#xA;“Load more” no more. As you scroll through your feed new posts transparently load in the background&#xA;Your reading position in a timeline is always preserved&#xA;View trending posts and links from your server&#xA;Use more than five tabs&#xA;Choose from a range of accessible fonts&#xA;A new media player component, supporting more video formats&#xA;Mark lists as “exclusive”. Posts from accounts on exclusive lists only appear in the list, not your home timeline&#xA;Add bookmarked posts to their own tab&#xA;Hide “self-boosts” from your timeline&#xA;&#xA;Bug fixes&#xA;&#xA;No more missing posts; Tusky and other apps can miss posts from your timeline, Pachli always shows the full timeline&#xA;Images don’t “stick” when you zoom or swipe between them&#xA;Search text is not deleted when you move between search tabs&#xA;Show server error messages, making it easier to understand why an operation failed&#xA;Filters now work in notifications&#xA;&#xA;UX changes&#xA;&#xA;A visual refresh and new colour scheme&#xA;Determine the default theme (light or dark) from your Android settings, not hardcoded to “dark”&#xA;Move “Clear notifications” to a menu to make it more difficult to trigger accidentally&#xA;Extend the list of available languages&#xA;&#xA;Download Pachli from Google Play and F-Droid.&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>After <a href="https://nikclayton.writeas.com/update-5-on-stepping-back" rel="nofollow">recent events</a> and looking at the existing open source Android Mastodon clients I decided there&#39;s space for one more, with a specific focus.</p>

<p><a href="https://nikclayton.writeas.com/tag:Pachli" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Pachli</span></a> (<a href="https://pachli.app" rel="nofollow">website</a>, <a href="https://play.google.com/store/apps/details?id=app.pachli" rel="nofollow">google play</a>, <a href="https://f-droid.org/packages/app.pachli" rel="nofollow">f-droid</a>, <a href="https://github.com/pachli/pachli-android" rel="nofollow">github</a>, <a href="https://mastodon.social/@pachli" rel="nofollow">mastodon</a>)</p>

<p>To quote from <a href="https://pachli.app/pachli/2023/09/06/hello-pachli.html:" rel="nofollow">https://pachli.app/pachli/2023/09/06/hello-pachli.html:</a></p>

<p>Pachli is an application (now) and an association (aspirational).</p>

<p>Pachli-the-application is a best-in-class open source Android application for Mastodon and Mastodon-like servers. If you’re familiar with Tusky then you’ll love Pachli.</p>

<p>Pachli-the-association is intended to provide a first class organisation to manage the development of the application under the <a href="https://www.ica.coop/en/cooperatives/cooperative-identity" rel="nofollow">7 cooperative principles</a>:</p>
<ol><li>Voluntary and open membership</li>
<li>Democratic member control</li>
<li>Member economic participation</li>
<li>Autonomy and independence</li>
<li>Education, Training, and Information</li>
<li>Cooperation among Cooperatives</li>
<li>Concern for Community</li></ol>

<p>The application is a rapidly iterating fork of the popular Tusky Mastodon client, branched from version 23.0 of that application.</p>

<p>Pachli includes many changes from Tusky 23.0, including:</p>

<p><strong>New features</strong></p>
<ul><li>“Load more” no more. As you scroll through your feed new posts transparently load in the background</li>
<li>Your reading position in a timeline is always preserved</li>
<li>View trending posts and links from your server</li>
<li>Use more than five tabs</li>
<li>Choose from a range of accessible fonts</li>
<li>A new media player component, supporting more video formats</li>
<li>Mark lists as “exclusive”. Posts from accounts on exclusive lists only appear in the list, not your home timeline</li>
<li>Add bookmarked posts to their own tab</li>
<li>Hide “self-boosts” from your timeline</li></ul>

<p><strong>Bug fixes</strong></p>
<ul><li>No more missing posts; Tusky and other apps can miss posts from your timeline, Pachli always shows the full timeline</li>
<li>Images don’t “stick” when you zoom or swipe between them</li>
<li>Search text is not deleted when you move between search tabs</li>
<li>Show server error messages, making it easier to understand why an operation failed</li>
<li>Filters now work in notifications</li></ul>

<p><strong>UX changes</strong></p>
<ul><li>A visual refresh and new colour scheme</li>
<li>Determine the default theme (light or dark) from your Android settings, not hardcoded to “dark”</li>
<li>Move “Clear notifications” to a menu to make it more difficult to trigger accidentally</li>
<li>Extend the list of available languages</li></ul>

<p><a href="https://pachli.app/download/" rel="nofollow">Download Pachli from Google Play and F-Droid</a>.</p>
]]></content:encoded>
      <guid>https://nikclayton.writeas.com/pachli</guid>
      <pubDate>Mon, 30 Oct 2023 16:25:40 +0000</pubDate>
    </item>
    <item>
      <title>Update #5 on &#34;Stepping back&#34;</title>
      <link>https://nikclayton.writeas.com/update-5-on-stepping-back?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Edit to add this set of links to the posts in the series&#xA;&#xA;Stepping back from the Tusky project&#xA;Update #1 on &#34;Stepping back&#34;&#xA;Update #2 on &#34;Stepping back&#34;&#xA;Update #3 on &#34;Stepping back&#34;&#xA;Update #4 on &#34;Stepping back&#34;&#xA;Final entry: Update #5 on &#34;Stepping back&#34;&#xA;&#xA;---&#xA;&#xA;In Update #2 on &#34;Stepping back&#34; I alleged that some of the public statements by the Tusky project, prompted by Stepping back from the Tusky project, were lies.&#xA;&#xA;It is my responsibility to present evidence for that. This is the last of a collection of posts that do that, or otherwise respond to the public statement by the Tusky team.&#xA;&#xA;  !NOTE] See also [Update #3 on &#34;Stepping back&#34; and Update #4 on &#34;Stepping back&#34;&#xA;&#xA;You may be reasonably concerned that the following selectively quotes from the discussion. To allay those concerns the full discussion is archived at chat.md. You might want to read that first, or have it open in another window.&#xA;&#xA;I have not addressed every statement made by the project in what follows. Blame Brandolini&#39;s law. Given the volume of trivially provable lies the project&#39;s contributors made in the statement they produced I leave it to you to decide how trustworthy the remainder of their comments are.&#xA;&#xA;The &#34;Conflict with Nik Clayton&#34; section&#xA;&#xA;  Nik would have expected to find documentation of the decision to hire Z, but in this case would not have been able to do so because the hiring predates our current project documentation process.&#xA;  \- Tusky Contributor response to Nik Clayton&#xA;&#xA;This is a lie. I was not asking for documentation for decision making around Mike&#39;s hiring.&#xA;&#xA;I was asking why the invoice showed a payment for work that was demonstrably not done.&#xA;&#xA;Even if Mike&#39;s contract was for time, not specific results, the invoice should have reflected that. E.g., &#34;X hours spent under contract Y&#34;.&#xA;&#xA;The three invoices actually said (in their entirety):&#xA;&#xA;&#34;First invoice submission to Tusky&#34;, #129964&#xA;&#34;Second invoice submission to Tusky&#34;, #123650&#xA;&#34;Work on &#39;bookmark tab&#39; feature (#2368); Work on &#39;copy hashtags into reply&#39; (#3013); Work on &#39;positional substitution format&#39; (#3297)&#34;, #125597&#xA;&#xA;---&#xA;&#xA;  When he was shown the documentation of what Z had done and why Z was paid for it, he was unable or unwilling to drop the matter&#xA;  \- Tusky Contributor response to Nik Clayton&#xA;&#xA;This is a lie. I was not shown documentation of what Mike had done.&#xA;&#xA;Had I been, that&#39;s still not relevant, because my concern was not &#34;What other work has Mike been doing?&#34; my concern was initially &#34;Why does invoice #125597 list work that was demonstrably not done?&#34;, followed  rapidly by &#34;And why are these other two invoices so generic?&#34;, then followed by &#34;Why is the response to what should be straightforward questions so hostile?&#34;&#xA;&#xA;There are three people who had admin rights to the Open Collective project and could respond; connyduck, tak, and maloki.&#xA;&#xA;Of those three, the only person who responded was maloki, and the entirety of her response pertaining to the work was the following two sentences.&#xA;&#xA;  It&#39;s soma, and we had an agreement that he&#39;d be paid for the first 3 months on an hourly basis with a max ceiling.&#xA;  Part of their work was also offloading me, and was supposed to be working on the FAQ, but you submitted your update of it while they were working on it.&#xA;&#xA;If you can straight-facedly refer to that as &#34;shown documentation of what Mike had done&#34;, well, you&#39;re a better dissembler than I am.&#xA;&#xA;Note also that the second sentence attempts to deflect blame on to me for apparently doing work that overlapped with Mike&#39;s.&#xA;&#xA;Given that my questions were not answered it is not surprising that I was &#34;unable or unwilling to drop the matter&#34;, and I replied:&#xA;&#xA;  My PR that updated the FAQ (also my first project contribution) was submitted on Dec 17 2022, and merged on Dec 22 2022. There was no public indication before then that anyone else was working on it.&#xA;    The three Mike Haynes invoices on OpenCollective have the following dates and descriptions (Mike Haynes - Open Collective):&#xA;    1. January 31, 2023 (&#34;First invoice submission to Tusky&#34;), 120964&#xA;  2. February 16, 2023 (&#34;Invoice for first half of February&#34;), 123650&#xA;  3. March 1, 2023 (&#34;Work on &#39;bookmark tab&#39; feature (#2368); Work on &#39;copy hashtags into reply&#39; (#3013); Work on &#39;positional substitution format&#39; (#3297)&#34;), 125597&#xA;    For the first two, what work was actually done? I can&#39;t find any PRs or issues (either open or closed) in the tuskyapp/tusky or tuskyapp/faq repositories that would match, and SomaRasu (Mike Haynes) · GitHub shows no apparent contributions.&#xA;    I assume there is a straightforward explanation for this, I&#39;d just like to know what it is.&#xA;    But as and when there&#39;s a legal structure backing Tusky this will not fly. Invoice 3, in particular, looks fraudulent.&#xA;    To be super clear -- I&#39;m 100% not saying it is fraudulent. This could be as simple as &#34;Some work was intended to be done, it wasn&#39;t, other work was done instead, and the expense description was not updated&#34;.&#xA;    But we should be able to explain what that work was, and we should have processes in place so that this does not happen again.&#xA;&#xA;I take a moment to note that some people have suggested that &#34;I&#39;m 100% not saying it is fraudulent&#34; is a weasel-worded way of trying to suggest that something is, in fact, fraudulent.&#xA;&#xA;With no other context, I could understand that point of view. However, this is not a context-free discussion. At this point I have been working on the project for approximately eight months, landed more than 150 PRs, replied to countless user questions from the Tusky account, and run the two most recent releases.&#xA;&#xA;And the project&#39;s statement says they had &#34;the intent of admin status being transitioned to him&#34; and described me as the &#34;primary code contributor&#34;. &#xA;&#xA;With that context it should be clear that raising any concerns like this are not an accusation of wrong doing, but an expression of concern that other people, without the relevant context, may look at the same information I did and assume fraud.&#xA;&#xA;Maloki did not take it that way, responding:&#xA;&#xA;  Can You stop?&#xA;  Because let it be clear, this attitude would mean that all my contribution also isn&#39;t valid and shouldn&#39;t have been paid for because there wasn&#39;t any proof.&#xA;  This is an admin issue. The admins had agreements in place with people involved.&#xA;&#xA;This is the first suggestion in the discussion that any of Maloki&#39;s contributions are questionable, and she raised it, not me.&#xA;&#xA;I was not the only person to think like this. Charles (charlag) wrote in response to the above:&#xA;&#xA;  mal with you I think it was quite different. I don&#39;t know anything about this (which is probably my fault) and to me it also looks very odd.&#xA;    if in your case it&#39;s a regular payment in this case it does really look like payment for work that wasn&#39;t done. I think big point of OC is transparency and this does not look good for us.&#xA;    should it have been labelled differently? as in, &#34;project management work&#34; or similar (I assume you mean that by offloading).&#xA;    I really don&#39;t think anyone is trying to put your contributions or payment into question but I agree that we should be transparent and should have a record of agreements&#xA;&#xA;Charles has clearly understood the context in which I asked the original question (&#34;I really don&#39;t think anyone is trying to put your contributions or payments into question&#34;).&#xA;&#xA;Maloki reiterates that she believes this information should not be transparent, replying to Charles:&#xA;&#xA;  When I&#39;m trying to explain I really don&#39;t appreciate a fucking wall of text about how I&#39;m clearly wrong. Like whatx the Fuck.&#xA;  And it&#39;s part of why we&#39;ve worked on improving the process. &#xA;  But all these conversations aren&#39;t going to be for and open to the contributors.  &#xA;  And for a long while it was mostly me and Conny that had a quick chat about stuff and agreed to things. And then course corrected as needed.&#xA;&#xA;During this discussion Mike writes:&#xA;&#xA;  I just want to say: this was work that was intended to be done, but unfortunately I couldn&#39;t get done, primarily due to my inability to wrap my head around getting a PR submitted. I did have code written for these issues, but I&#39;m not sure if I still have them stashed or not.  &#xA;  I&#39;m really sorry for any confusion I caused and for how I approached the OC invoice system. Conny had told me going forward if I were to submit any invoices that a PR(s) needed to be provided&#xA;&#xA;I start a 1:1 discussion with him to see about getting any of the that he did do merged in to the project. That takes about two hours over two days, and one PR is merged the next day (more details in Update #3 on &#34;Stepping back&#34;). The work for the other two invoices is, to the best of my knowledge, still not complete.&#xA;&#xA;Separately, I respond in the channel to Maloki.&#xA;&#xA;  Your explanation didn&#39;t (and still hasn&#39;t) addressed the &#34;Why has an invoice been paid that describes work on three specific GitHub issues, when all available evidence shows that no work was done on those issues?&#34;.&#xA;    The explanation could be as simple as &#34;Admin mistake, they worked on X, Y, and Z instead, we forgot to update the description in OC&#34;.&#xA;&#xA;This question is still unanswered.&#xA;&#xA;---&#xA;&#xA;  but we as observers to the conversation feel that Maloki was generally only responding with the same harsh tone that she was being addressed in&#xA;  \- Tusky Contributor response to Nik Clayton&#xA;&#xA;I will let readers decide whether my tone was harsh. As already noted, the complete chat logs are at chat.md.&#xA;&#xA;  Multiple contributors had asked Nik to slow down or temporarily stop because they had no capacity to respond, for valid health reasons including hospitalization&#xA;&#xA;The only people who could answer the questions authoratively were the project&#39;s three financial admins on Open Collective. They were:&#xA;&#xA;ConnyDuck (stepped down)&#xA;Maloki (still active)&#xA;Tak (still active, did not respond during the discussion)&#xA;&#xA;Maloki repeatedly asked for the discussion to stop, saying (over multiple messages):&#xA;&#xA;  Can You stop? [...] This is an admin issue. The admins had agreements in place with people involved.&#xA;&#xA;!-- --&#xA;&#xA;  these conversations aren&#39;t going to be for and open to the contributors.&#xA;&#xA;!-- --&#xA;&#xA;  it&#39;s not a question that necessarily should be posed in the contributors channel&#xA;&#xA;!-- --&#xA;&#xA;  the contracts and agreements we make with people is not for public consumption, and I don&#39;t believe they have to be, which is why I was very thorns out on this question. You don&#39;t need to know any details of the agreement whatsoever besides &#34;this was a past agreement and it got paid for&#34;.&#xA;&#xA;As already noted, Charles was the first person to reply, and replied several times during the discussion despite health issues. Charles is not an active financial admin for the project on Open Collective, and the contributions (although helpful) were unasked for, and the decision to join the discussion was their own.&#xA;&#xA;---&#xA;&#xA;  Nik insisted on his solution and that it be implemented immediately.&#xA;  \- Tusky Contributor response to Nik Clayton&#xA;&#xA;This is a lie.&#xA;&#xA;While the discussion was going I hastily organised my thoughts in to a strawman proposal for an expenses policy and a grants policy, and wrote them up. I had hoped that these would stop the discussion from spiralling down the drain of what had already happened, and allow us to productively focus on active changes we could make to stop it happening in the future.&#xA;&#xA;They are clearly not ready to be &#34;implemented immediately&#34; as there are a number of TODOs, and a significant number of open questions for discussion in the grants policy.&#xA;&#xA;I presented this to the group as:&#xA;&#xA;  [...] Since a more specific expense and grant policy might be useful, I&#39;ve thrown these together for discussion:&#xA;    - https://gist.github.com/nikclayton/5c4118c7f153b0a8ade904cfccde5fdd&#xA;  - https://gist.github.com/nikclayton/bd1146e24e97b113c6d14f31bbd8a36c&#xA;    As you&#39;ll see, plenty of open questions on both.&#xA;&#xA;and &#xA;&#xA;  ...] The clearest explanation you will see of this is my strawman proposals for an expenses policy ([https://gist.github.com/nikclayton/5c4118c7f153b0a8ade904cfccde5fdd) and a grants policy (https://gist.github.com/nikclayton/bd1146e24e97b113c6d14f31bbd8a36c).&#xA;    Since we definitely have strong differences of opinion around project governance and finance issues, and since those documents set out my current thinking, could you review those, and provide feedback?&#xA;&#xA;There was no feedback on these from anyone, and I never mentioned them again in the chat.&#xA;&#xA;I know I&#39;ve already said it, but to be clear, any suggestion that I had a solution and insisted it be implemented immediately is a lie.&#xA;&#xA;---&#xA;&#xA;  By the time the week came to a close, Maloki felt the conversation had spiraled out of her ability to de-escalate&#xA;  \- Tusky Contributor response to Nik Clayton&#xA;&#xA;I had already made multiple attempts to de-escalate the discussion, including:&#xA;&#xA;Working with Mike to review and approve one of his contributions&#xA;Suggesting clear explanations for what may have happened&#xA;Proposing the bones of possible future policies, using what could be learned from this issue&#xA;&#xA;Maloki refused to engage with any of these. As already noted, the only thing she seemed to want to do was shut the discussion down.&#xA;&#xA;  Mcc and Maloki were going to introduce Nik and the other contributors to L.J. within 24 hours and let her propose a process for resolving the conflict, but did not get the chance&#xA;  \- Tusky Contributor response to Nik Clayton&#xA;&#xA;I have no idea how true this is. Obviously, I had no knowledge of it at the time.&#xA;&#xA;I note that Maloki&#39;s last message in the discussion (to which I did not respond) was:&#xA;&#xA;  We&#39;re not tone policing the issue. We&#39;re specifically asking you to stop.&#xA;&#xA;This was sent 2023-08-25 (Friday) at 13:08 CEST.&#xA;&#xA;Not &#34;pause&#34;. Not &#34;wait until we can gather some more information&#34;. Not &#34;wait until I can get a mediator&#34;.&#xA;&#xA;From my perspective the discussion was over. I had raised what I thought were reasonable concerns, in the correct forum, and been given incomplete and evasive information. Clarifying questions resulted in demands that the discussion be shut down, and my attempt to redirect the conversation to a more productive &#34;Here&#39;s how we could do things in the future&#34; direction were ignored.&#xA;&#xA;At that point further discussion or engagement seemed both futile, and was also directly contrary to Maloki&#39;s final message.&#xA;&#xA;After drafting the blog post, getting some trusted friends and former colleagues to review it, and modifying it based on their feedback, I posted a brief resignation note on the contributors channel (with instructions on how to remove me from the shared project infrastructure).&#xA;&#xA;--- &#xA;&#xA;The &#34;Payments which Nik has questioned&#34; section&#xA;&#xA;  We, the remaining Tusky contributors, have several issues with Nik&#39;s post. We disagree, based on the information that both we and Nik have been given, that the payments Nik objects to were inappropriate at the time.&#xA;  \- Tusky Contributor response to Nik Clayton&#xA;&#xA;I&#39;ll be (mercifully) brief here, because this section mischaracterises what I was saying, and then argues against that mischaracterisation.&#xA;&#xA;So, for the nth time -- I do not think that the payments were inappropriate, given the context that was provided in the discussion.&#xA;&#xA;I still think:&#xA;&#xA;The invoices did not follow the OC policy&#xA;Maloki&#39;s response, demanding that the discussion be stopped, that it was not appropriate for contributors, and that contributors should not have a role in holding the financial admins to account is completely inappropriate&#xA;&#xA;  We also object to how he mischaracterizes the positions of Tusky as a project&#xA;  \- Tusky Contributor response to Nik Clayton&#xA;&#xA;I am always happy to correct anything that I&#39;ve written. If anyone from the team can (a) point to something specific, (b) let me know about you think is a mischaracterisation, and why, and I agree with you, I will correct it, and post about the correction.&#xA;&#xA;  and feel that he retroactively imposed future_ standards, which would apply should we move forward with the idea to incorporate the Tusky project, to past leadership’s decisions.&#xA;  \- Tusky Contributor response to Nik Clayton&#xA;&#xA;Again, a mischaracterisation. Also, a deflection.&#xA;&#xA;First, my expectations of how a financial admin should behave when responding to questions is not related to past leadership decisions.&#xA;&#xA;It may be what past leadership has tolerated -- I was only involved with the project for eight months, so I can&#39;t speak to that.&#xA;&#xA;Second, my standards are second to the legal agreements that the project entered in to when it signed the agreements with Open Collective and the Open Source Collective (OSC) as the project&#39;s fiscal host (yes, the the fact that two different organisations have such a close name is confusing).&#xA;&#xA;Unfortunately, I can&#39;t tell what the agreement the project signed says, because the financial admins don&#39;t think it&#39;s appropriate. All I can do, as I have done, is point to where I think the project may have breached them either in fact or in spirit.&#xA;&#xA;The &#34;What Does Tusky Use Donor Money For?&#34; section&#xA;&#xA;  we actively solicit people outside the project when there is work which needs to be done but which no one is available to do&#xA;  \- Tusky Contributor response to Nik Clayton&#xA;&#xA;I believe, but cannot prove with 100% confidence, that this is a lie.&#xA;&#xA;  !NOTE] See also [Update #2 on &#34;Stepping back&#34; — nikclayton&#xA;&#xA;Demonstrating some proof of active solicitation of people outside the project should be straightforward.&#xA;&#xA;For the past four and a half years the project has paid (Tusky · Expenses - Open Collective, and ignoring the payments to Mike which I have already noted):&#xA;&#xA;1 payment to a Slovenian translator&#xA;Annual payments for the tusky.app domain registration&#xA;1 payment to a Brazilian translator&#xA;Payments for new artwork&#xA;Multiple payments in 2023 to a new code contributor&#xA;&#xA;The remaining payments have been to Maloki, one of the financial admins.&#xA;&#xA;In those same four and a half years the project did not actively solicit people outside the project by:&#xA;&#xA;Developing a coherent expense or grants policy, despite promising to in We are setting up a way to support us! - Open Collective and Thank you very much for your donations! - Open Collective&#xA;Posting updates to Tusky - Open Collective asking potential contributors who needed financial support to apply&#xA;Mentioning that financial support for contributors was available in the project&#39;s CONTRIBUTING.md file or README.md file.&#xA;Asking new contributors to the project if they needed financial support&#xA;Mentioning the availability of financial support in the release notes, Releases · tuskyapp/Tusky (although the release notes generally mentioned the ability to donate)&#xA;Mentioning it in the &#34;About&#34; section for the project on OpenCollective. At the time of writing this briefly describes the project and its features.&#xA;Mentioning it at https://www.tusky.app, the project&#39;s public website.&#xA;Mentioning it in the Google Play Store listing&#xA;Mentioning it in the F-Droid listing&#xA;Linking to anything describing the availability of financial support from the project&#39;s &#34;Bio&#34; fields in the Tusky Mastodon profile&#xA;Posting from the project&#39;s Mastodon account telling people to apply for financial support (searching the account&#39;s public posts for &#34;support&#34;, &#34;sponsor&#34;, &#34;contribute&#34;, &#34;grant&#34;, &#34;expense&#34;, &#34;opencollective&#34; shows no posts describing work that needs to be done in exchange for financial support)&#xA;&#xA;The only other place I could think to check is if the Tusky Mastodon account received DMs from people asking for contributions.&#xA;&#xA;Obviously I don&#39;t have access to that, and even if the project was receiving those requests, the public payment history on Open Collective demonstrates that the project was generally not making payments to outside contributors.&#xA;&#xA;I would be delighted to document the ways in which the Tusky project actively solicited people outside the project, should the project provide any.&#xA;&#xA;But until that time, I believe the project is demonstrably, repeatedly, lying to you.&#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>Edit to add this set of links to the posts in the series</p>
<ul><li><a href="https://write.as/nikclayton/stepping-back-from-the-tusky-project" rel="nofollow">Stepping back from the Tusky project</a></li>
<li><a href="https://write.as/nikclayton/update-on-1-stepping-back" rel="nofollow">Update #1 on “Stepping back”</a></li>
<li><a href="https://write.as/nikclayton/update-2-on-stepping-back" rel="nofollow">Update #2 on “Stepping back”</a></li>
<li><a href="https://write.as/nikclayton/update-3-on-stepping-back" rel="nofollow">Update #3 on “Stepping back”</a></li>
<li><a href="https://write.as/nikclayton/update-4-on-stepping-back" rel="nofollow">Update #4 on “Stepping back”</a></li>
<li>Final entry: <a href="https://write.as/nikclayton/update-5-on-stepping-back" rel="nofollow">Update #5 on “Stepping back”</a></li></ul>

<hr/>

<p>In <a href="https://write.as/nikclayton/update-2-on-stepping-back" rel="nofollow">Update #2 on “Stepping back”</a> I alleged that some of the public statements by the Tusky project, prompted by <a href="https://write.as/nikclayton/stepping-back-from-the-tusky-project" rel="nofollow">Stepping back from the Tusky project</a>, were lies.</p>

<p>It is my responsibility to present evidence for that. This is the last of a collection of posts that do that, or otherwise respond to the <a href="https://opencollective.com/tusky/updates/tusky-contributor-response-to-nik-clayton" rel="nofollow">public statement by the Tusky team</a>.</p>

<blockquote><p>[!NOTE] See also <a href="https://write.as/nikclayton/update-3-on-stepping-back" rel="nofollow">Update #3 on “Stepping back”</a> and <a href="https://write.as/nikclayton/update-4-on-stepping-back" rel="nofollow">Update #4 on “Stepping back”</a></p></blockquote>

<p>You may be reasonably concerned that the following selectively quotes from the discussion. To allay those concerns the full discussion is archived at <a href="https://gist.github.com/nikclayton/ac2f724baf7b009cfa8bf17c35a4fdbe" rel="nofollow">chat.md</a>. You might want to read that first, or have it open in another window.</p>

<p>I have not addressed every statement made by the project in what follows. Blame <a href="https://en.wikipedia.org/wiki/Brandolini%27s_law" rel="nofollow">Brandolini&#39;s law</a>. Given the volume of trivially provable lies the project&#39;s contributors made in the statement they produced I leave it to you to decide how trustworthy the remainder of their comments are.</p>

<h2 id="the-conflict-with-nik-clayton-section" id="the-conflict-with-nik-clayton-section">The “Conflict with Nik Clayton” section</h2>

<blockquote><p>Nik would have expected to find documentation of the decision to hire Z, but in this case would not have been able to do so because the hiring predates our current project documentation process.
- <a href="https://opencollective.com/tusky/updates/tusky-contributor-response-to-nik-clayton" rel="nofollow">Tusky Contributor response to Nik Clayton</a></p></blockquote>

<p><strong>This is a lie</strong>. I was not asking for documentation for decision making around Mike&#39;s hiring.</p>

<p>I was asking why the invoice showed a payment for work that was demonstrably not done.</p>

<p>Even if Mike&#39;s contract was for time, not specific results, the invoice should have reflected that. E.g., “X hours spent under contract Y”.</p>

<p>The three invoices actually said (in their entirety):</p>
<ul><li>“First invoice submission to Tusky”, <a href="https://opencollective.com/tusky/expenses/120964" rel="nofollow">#129964</a></li>
<li>“Second invoice submission to Tusky”, <a href="https://opencollective.com/tusky/expenses/123650" rel="nofollow">#123650</a></li>
<li>“Work on &#39;bookmark tab&#39; feature (#2368); Work on &#39;copy hashtags into reply&#39; (#3013); Work on &#39;positional substitution format&#39; (#3297)”, <a href="https://opencollective.com/tusky/expenses/125597" rel="nofollow">#125597</a></li></ul>

<hr/>

<blockquote><p>When he <em>was</em> shown the documentation of what Z had done and why Z was paid for it, he was unable or unwilling to drop the matter
- <a href="https://opencollective.com/tusky/updates/tusky-contributor-response-to-nik-clayton" rel="nofollow">Tusky Contributor response to Nik Clayton</a></p></blockquote>

<p><strong>This is a lie</strong>. I was not shown documentation of what Mike had done.</p>

<p>Had I been, that&#39;s still not relevant, because my concern was not “What other work has Mike been doing?” my concern was initially “Why does invoice #125597 list work that was demonstrably not done?”, followed  rapidly by “And why are these other two invoices so generic?”, then followed by “Why is the response to what should be straightforward questions so hostile?”</p>

<p>There are three people who had admin rights to the Open Collective project and could respond; connyduck, tak, and maloki.</p>

<p>Of those three, the only person who responded was maloki, and the entirety of her response pertaining to the work was the following two sentences.</p>

<blockquote><p>It&#39;s soma, and we had an agreement that he&#39;d be paid for the first 3 months on an hourly basis with a max ceiling.
Part of their work was also offloading me, and was supposed to be working on the FAQ, but you submitted your update of it while they were working on it.</p></blockquote>

<p>If you can straight-facedly refer to that as “shown documentation of what Mike had done”, well, you&#39;re a better dissembler than I am.</p>

<p>Note also that the second sentence attempts to deflect blame on to me for apparently doing work that overlapped with Mike&#39;s.</p>

<p>Given that my questions were not answered it is not surprising that I was “unable or unwilling to drop the matter”, and I replied:</p>

<blockquote><p>My PR that updated the FAQ (also my first project contribution) was submitted on Dec 17 2022, and merged on Dec 22 2022. There was no public indication before then that anyone else was working on it.</p>

<p>The three Mike Haynes invoices on OpenCollective have the following dates and descriptions (<a href="https://opencollective.com/mike-haynes" rel="nofollow">Mike Haynes – Open Collective</a>):</p>
<ol><li>January 31, 2023 (“First invoice submission to Tusky”), <a href="https://opencollective.com/tusky/expenses/120964" rel="nofollow">120964</a></li>
<li>February 16, 2023 (“Invoice for first half of February”), <a href="https://opencollective.com/tusky/expenses/123650" rel="nofollow">123650</a></li>
<li>March 1, 2023 (“Work on &#39;bookmark tab&#39; feature (#2368); Work on &#39;copy hashtags into reply&#39; (#3013); Work on &#39;positional substitution format&#39; (#3297)”), <a href="https://opencollective.com/tusky/expenses/125597" rel="nofollow">125597</a></li></ol>

<p>For the first two, what work was actually done? I can&#39;t find any PRs or issues (either open or closed) in the <code>tuskyapp/tusky</code> or <code>tuskyapp/faq</code> repositories that would match, and <a href="https://github.com/SomaRasu" rel="nofollow">SomaRasu (Mike Haynes) · GitHub</a> shows no apparent contributions.</p>

<p>I assume there is a straightforward explanation for this, I&#39;d just like to know what it is.</p>

<p>But as and when there&#39;s a legal structure backing Tusky this will not fly. Invoice 3, in particular, looks fraudulent.</p>

<p>To be super clear — <strong>I&#39;m 100% not saying it is fraudulent</strong>. This could be as simple as “Some work was intended to be done, it wasn&#39;t, other work was done instead, and the expense description was not updated”.</p>

<p>But we should be able to explain what that work was, and we should have processes in place so that this does not happen again.</p></blockquote>

<p>I take a moment to note that some people have suggested that “I&#39;m 100% not saying it is fraudulent” is a weasel-worded way of trying to suggest that something is, in fact, fraudulent.</p>

<p>With no other context, I could understand that point of view. However, this is not a context-free discussion. At this point I have been working on the project for approximately eight months, landed more than 150 PRs, replied to countless user questions from the Tusky account, and run the two most recent releases.</p>

<p>And the project&#39;s statement says they had “the intent of admin status being transitioned to him” and described me as the “primary code contributor”.</p>

<p>With that context it should be clear that raising any concerns like this are not an accusation of wrong doing, but an expression of concern that other people, without the relevant context, may look at the same information I did and assume fraud.</p>

<p>Maloki did not take it that way, responding:</p>

<blockquote><p>Can You stop?
Because let it be clear, this attitude would mean that all my contribution also isn&#39;t valid and shouldn&#39;t have been paid for because there wasn&#39;t any proof.
This is an admin issue. The admins had agreements in place with people involved.</p></blockquote>

<p>This is the first suggestion in the discussion that any of Maloki&#39;s contributions are questionable, and she raised it, not me.</p>

<p>I was not the only person to think like this. Charles (charlag) wrote in response to the above:</p>

<blockquote><p>mal with you I think it was quite different. I don&#39;t know anything about this (which is probably my fault) and to me it also looks very odd.</p>

<p>if in your case it&#39;s a regular payment in this case it does really look like payment for work that wasn&#39;t done. I think big point of OC is transparency and this does not look good for us.</p>

<p>should it have been labelled differently? as in, “project management work” or similar (I assume you mean that by offloading).</p>

<p>I really don&#39;t think anyone is trying to put your contributions or payment into question but I agree that we should be transparent and should have a record of agreements</p></blockquote>

<p>Charles has clearly understood the context in which I asked the original question (“I really don&#39;t think anyone is trying to put your contributions or payments into question”).</p>

<p>Maloki reiterates that she believes this information should not be transparent, replying to Charles:</p>

<blockquote><p>When I&#39;m trying to explain I really don&#39;t appreciate a fucking wall of text about how I&#39;m clearly wrong. Like whatx the Fuck.
And it&#39;s part of why we&#39;ve worked on improving the process.
But all these conversations aren&#39;t going to be for and open to the contributors.<br/>
And for a long while it was mostly me and Conny that had a quick chat about stuff and agreed to things. And then course corrected as needed.</p></blockquote>

<p>During this discussion Mike writes:</p>

<blockquote><p>I just want to say: this was work that was intended to be done, but unfortunately I couldn&#39;t get done, primarily due to my inability to wrap my head around getting a PR submitted. I did have code written for these issues, but I&#39;m not sure if I still have them stashed or not.<br/>
I&#39;m really sorry for any confusion I caused and for how I approached the OC invoice system. Conny had told me going forward if I were to submit any invoices that a PR(s) needed to be provided</p></blockquote>

<p>I start a 1:1 discussion with him to see about getting any of the that he did do merged in to the project. That takes about two hours over two days, and one PR is merged the next day (more details in <a href="https://write.as/nikclayton/update-3-on-stepping-back" rel="nofollow">Update #3 on “Stepping back”</a>). The work for the other two invoices is, to the best of my knowledge, still not complete.</p>

<p>Separately, I respond in the channel to Maloki.</p>

<blockquote><p>Your explanation didn&#39;t (and still hasn&#39;t) addressed the “Why has an invoice been paid that describes work on three specific GitHub issues, when all available evidence shows that no work was done on those issues?”.</p>

<p>The explanation could be as simple as “Admin mistake, they worked on X, Y, and Z instead, we forgot to update the description in OC”.</p></blockquote>

<p>This question is still unanswered.</p>

<hr/>

<blockquote><p>but we as observers to the conversation feel that Maloki was generally only responding with the same harsh tone that she was being addressed in
- <a href="https://opencollective.com/tusky/updates/tusky-contributor-response-to-nik-clayton" rel="nofollow">Tusky Contributor response to Nik Clayton</a></p></blockquote>

<p>I will let readers decide whether my tone was harsh. As already noted, the complete chat logs are at <a href="https://gist.github.com/nikclayton/ac2f724baf7b009cfa8bf17c35a4fdbe" rel="nofollow">chat.md</a>.</p>

<blockquote><p>Multiple contributors had asked Nik to slow down or temporarily stop because they had no capacity to respond, for valid health reasons including hospitalization</p></blockquote>

<p>The only people who could answer the questions authoratively were the project&#39;s three financial admins on Open Collective. They were:</p>
<ul><li>ConnyDuck (stepped down)</li>
<li>Maloki (still active)</li>
<li>Tak (still active, did not respond during the discussion)</li></ul>

<p>Maloki repeatedly asked for the discussion to stop, saying (over multiple messages):</p>

<blockquote><p>Can You stop? [...] This is an admin issue. The admins had agreements in place with people involved.</p></blockquote>



<blockquote><p>these conversations aren&#39;t going to be for and open to the contributors.</p></blockquote>



<blockquote><p>it&#39;s not a question that necessarily should be posed in the contributors channel</p></blockquote>



<blockquote><p>the contracts and agreements we make with people is not for public consumption, and I don&#39;t believe they have to be, which is why I was very thorns out on this question. You don&#39;t need to know any details of the agreement whatsoever besides “this was a past agreement and it got paid for”.</p></blockquote>

<p>As already noted, Charles was the first person to reply, and replied several times during the discussion despite health issues. Charles is not an active financial admin for the project on Open Collective, and the contributions (although helpful) were unasked for, and the decision to join the discussion was their own.</p>

<hr/>

<blockquote><p>Nik insisted on his solution and that it be implemented immediately.
- <a href="https://opencollective.com/tusky/updates/tusky-contributor-response-to-nik-clayton" rel="nofollow">Tusky Contributor response to Nik Clayton</a></p></blockquote>

<p><strong>This is a lie</strong>.</p>

<p>While the discussion was going I hastily organised my thoughts in to a strawman proposal for an expenses policy and a grants policy, and wrote them up. I had hoped that these would stop the discussion from spiralling down the drain of what had already happened, and allow us to productively focus on active changes we could make to stop it happening in the future.</p>

<p>They are clearly not ready to be “<em>implemented immediately</em>” as there are a number of TODOs, and a significant number of open questions for discussion in the grants policy.</p>

<p>I presented this to the group as:</p>

<blockquote><p>[...] Since a more specific expense and grant policy might be useful, I&#39;ve thrown these together for discussion:</p>
<ul><li><a href="https://gist.github.com/nikclayton/5c4118c7f153b0a8ade904cfccde5fdd" rel="nofollow">https://gist.github.com/nikclayton/5c4118c7f153b0a8ade904cfccde5fdd</a></li>
<li><a href="https://gist.github.com/nikclayton/bd1146e24e97b113c6d14f31bbd8a36c" rel="nofollow">https://gist.github.com/nikclayton/bd1146e24e97b113c6d14f31bbd8a36c</a></li></ul>

<p>As you&#39;ll see, plenty of open questions on both.</p></blockquote>

<p>and</p>

<blockquote><p>[...] The clearest explanation you will see of this is my strawman proposals for an expenses policy (<a href="https://gist.github.com/nikclayton/5c4118c7f153b0a8ade904cfccde5fdd" rel="nofollow">https://gist.github.com/nikclayton/5c4118c7f153b0a8ade904cfccde5fdd</a>) and a grants policy (<a href="https://gist.github.com/nikclayton/bd1146e24e97b113c6d14f31bbd8a36c" rel="nofollow">https://gist.github.com/nikclayton/bd1146e24e97b113c6d14f31bbd8a36c</a>).</p>

<p>Since we definitely have strong differences of opinion around project governance and finance issues, and since those documents set out my current thinking, could you review those, and provide feedback?</p></blockquote>

<p>There was no feedback on these from anyone, and I never mentioned them again in the chat.</p>

<p>I know I&#39;ve already said it, but to be clear, any suggestion that I had a solution and insisted it be implemented immediately <strong>is a lie</strong>.</p>

<hr/>

<blockquote><p>By the time the week came to a close, Maloki felt the conversation had spiraled out of her ability to de-escalate
- <a href="https://opencollective.com/tusky/updates/tusky-contributor-response-to-nik-clayton" rel="nofollow">Tusky Contributor response to Nik Clayton</a></p></blockquote>

<p>I had already made multiple attempts to de-escalate the discussion, including:</p>
<ul><li>Working with Mike to review and approve one of his contributions</li>
<li>Suggesting clear explanations for what may have happened</li>
<li>Proposing the bones of possible future policies, using what could be learned from this issue</li></ul>

<p>Maloki refused to engage with any of these. As already noted, the only thing she seemed to want to do was shut the discussion down.</p>

<blockquote><p>Mcc and Maloki were going to introduce Nik and the other contributors to L.J. within 24 hours and let her propose a process for resolving the conflict, but did not get the chance
- <a href="https://opencollective.com/tusky/updates/tusky-contributor-response-to-nik-clayton" rel="nofollow">Tusky Contributor response to Nik Clayton</a></p></blockquote>

<p>I have no idea how true this is. Obviously, I had no knowledge of it at the time.</p>

<p>I note that Maloki&#39;s last message in the discussion (to which I did not respond) was:</p>

<blockquote><p>We&#39;re not tone policing the issue. We&#39;re specifically asking you to stop.</p></blockquote>

<p>This was sent 2023-08-25 (Friday) at 13:08 CEST.</p>

<p>Not “pause”. Not “wait until we can gather some more information”. Not “wait until I can get a mediator”.</p>

<p>From my perspective the discussion was over. I had raised what I thought were reasonable concerns, in the correct forum, and been given incomplete and evasive information. Clarifying questions resulted in demands that the discussion be shut down, and my attempt to redirect the conversation to a more productive “Here&#39;s how we could do things in the future” direction were ignored.</p>

<p>At that point further discussion or engagement seemed both futile, and was also directly contrary to Maloki&#39;s final message.</p>

<p>After drafting the blog post, getting some trusted friends and former colleagues to review it, and modifying it based on their feedback, I posted a brief resignation note on the contributors channel (with instructions on how to remove me from the shared project infrastructure).</p>

<hr/>

<h2 id="the-payments-which-nik-has-questioned-section" id="the-payments-which-nik-has-questioned-section">The “Payments which Nik has questioned” section</h2>

<blockquote><p>We, the remaining Tusky contributors, have several issues with Nik&#39;s post. We disagree, based on the information that both we and Nik have been given, that the payments Nik objects to were inappropriate at the time.
- <a href="https://opencollective.com/tusky/updates/tusky-contributor-response-to-nik-clayton" rel="nofollow">Tusky Contributor response to Nik Clayton</a></p></blockquote>

<p>I&#39;ll be (mercifully) brief here, because this section mischaracterises what I was saying, and then argues against that mischaracterisation.</p>

<p>So, for the nth time — I do not think that the payments were inappropriate, given the context that was provided in the discussion.</p>

<p>I still think:</p>
<ol><li>The invoices did not follow the OC policy</li>
<li>Maloki&#39;s response, demanding that the discussion be stopped, that it was not appropriate for contributors, and that contributors should not have a role in holding the financial admins to account is completely inappropriate</li></ol>

<blockquote><p>We also object to how he mischaracterizes the positions of Tusky as a project
- <a href="https://opencollective.com/tusky/updates/tusky-contributor-response-to-nik-clayton" rel="nofollow">Tusky Contributor response to Nik Clayton</a></p></blockquote>

<p>I am always happy to correct anything that I&#39;ve written. If anyone from the team can (a) point to something specific, (b) let me know about you think is a mischaracterisation, and why, and I agree with you, I will correct it, and post about the correction.</p>

<blockquote><p>and feel that he retroactively imposed <em>future</em> standards, which would apply should we move forward with the idea to incorporate the Tusky project, to past leadership’s decisions.
- <a href="https://opencollective.com/tusky/updates/tusky-contributor-response-to-nik-clayton" rel="nofollow">Tusky Contributor response to Nik Clayton</a></p></blockquote>

<p>Again, a mischaracterisation. Also, a deflection.</p>

<p>First, my expectations of how a financial admin should behave when responding to questions is not related to past leadership decisions.</p>

<p>It may be what past leadership has tolerated — I was only involved with the project for eight months, so I can&#39;t speak to that.</p>

<p>Second, my standards are second to the legal agreements that the project entered in to when it signed the agreements with Open Collective and the Open Source Collective (OSC) as the project&#39;s fiscal host (yes, the the fact that two different organisations have such a close name is confusing).</p>

<p>Unfortunately, I can&#39;t tell what the agreement the project signed says, because the financial admins don&#39;t think it&#39;s appropriate. All I can do, as I have done, is point to where I think the project may have breached them either in fact or in spirit.</p>

<h2 id="the-what-does-tusky-use-donor-money-for-section" id="the-what-does-tusky-use-donor-money-for-section">The “What Does Tusky Use Donor Money For?” section</h2>

<blockquote><p>we actively solicit people outside the project when there is work which needs to be done but which no one is available to do
- <a href="https://opencollective.com/tusky/updates/tusky-contributor-response-to-nik-clayton" rel="nofollow">Tusky Contributor response to Nik Clayton</a></p></blockquote>

<p>I believe, but cannot prove with 100% confidence, that this is a lie.</p>

<blockquote><p>[!NOTE] See also <a href="https://write.as/nikclayton/update-2-on-stepping-back#policy-for-paying-contributors" rel="nofollow">Update #2 on “Stepping back” — nikclayton</a></p></blockquote>

<p>Demonstrating some proof of active solicitation of people outside the project should be straightforward.</p>

<p>For the past four and a half years the project has paid (<a href="https://opencollective.com/tusky/expenses" rel="nofollow">Tusky · Expenses – Open Collective</a>, and ignoring the payments to Mike which I have already noted):</p>
<ul><li>1 payment to a Slovenian translator</li>
<li>Annual payments for the tusky.app domain registration</li>
<li>1 payment to a Brazilian translator</li>
<li>Payments for new artwork</li>
<li>Multiple payments in 2023 to a new code contributor</li></ul>

<p>The remaining payments have been to Maloki, one of the financial admins.</p>

<p>In those same four and a half years the project <strong>did not</strong> actively solicit people outside the project by:</p>
<ul><li>Developing a coherent expense or grants policy, despite promising to in <a href="https://opencollective.com/tusky/updates/we-are-setting-up-a-way-to-support-us" rel="nofollow">We are setting up a way to support us! – Open Collective</a> and <a href="https://opencollective.com/tusky/updates/thank-you-very-much-for-your-donations" rel="nofollow">Thank you very much for your donations! – Open Collective</a></li>
<li>Posting updates to <a href="https://opencollective.com/tusky/updates" rel="nofollow">Tusky – Open Collective</a> asking potential contributors who needed financial support to apply</li>
<li>Mentioning that financial support for contributors was available in the project&#39;s <a href="https://github.com/tuskyapp/Tusky/blob/develop/CONTRIBUTING.md" rel="nofollow">CONTRIBUTING.md</a> file or <a href="https://github.com/tuskyapp/Tusky/blob/develop/README.md" rel="nofollow">README.md</a> file.</li>
<li>Asking new contributors to the project if they needed financial support</li>
<li>Mentioning the availability of financial support in the release notes, <a href="https://github.com/tuskyapp/Tusky/releases" rel="nofollow">Releases · tuskyapp/Tusky</a> (although the release notes generally mentioned the ability to donate)</li>
<li>Mentioning it in the “<a href="https://opencollective.com/tusky#category-ABOUT" rel="nofollow">About</a>” section for the project on OpenCollective. At the time of writing this briefly describes the project and its features.</li>
<li>Mentioning it at <a href="https://www.tusky.app" rel="nofollow">https://www.tusky.app</a>, the project&#39;s public website.</li>
<li>Mentioning it in the <a href="https://play.google.com/store/apps/details?id=com.keylesspalace.tusky" rel="nofollow">Google Play Store listing</a></li>
<li>Mentioning it in the <a href="https://f-droid.org/en/packages/com.keylesspalace.tusky/" rel="nofollow">F-Droid listing</a></li>
<li>Linking to anything describing the availability of financial support from the project&#39;s “Bio” fields in the Tusky Mastodon profile</li>
<li>Posting from the project&#39;s Mastodon account telling people to apply for financial support (searching the account&#39;s <a href="https://mastodon.social/@Tusky" rel="nofollow">public posts</a> for “support”, “sponsor”, “contribute”, “grant”, “expense”, “opencollective” shows no posts describing work that needs to be done in exchange for financial support)</li></ul>

<p>The only other place I could think to check is if the Tusky Mastodon account received DMs from people asking for contributions.</p>

<p>Obviously I don&#39;t have access to that, and even if the project <em>was</em> receiving those requests, the public payment history on Open Collective demonstrates that the project was generally not making payments to outside contributors.</p>

<p>I would be <em>delighted</em> to document the ways in which the Tusky project actively solicited people outside the project, should the project provide any.</p>

<p>But until that time, I believe the project is demonstrably, repeatedly, lying to you.</p>
]]></content:encoded>
      <guid>https://nikclayton.writeas.com/update-5-on-stepping-back</guid>
      <pubDate>Sun, 17 Sep 2023 14:13:07 +0000</pubDate>
    </item>
    <item>
      <title>Update #4 on &#34;Stepping back&#34;</title>
      <link>https://nikclayton.writeas.com/update-4-on-stepping-back?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Edit to add this set of links to the posts in the series&#xA;&#xA;Stepping back from the Tusky project&#xA;Update #1 on &#34;Stepping back&#34;&#xA;Update #2 on &#34;Stepping back&#34;&#xA;Update #3 on &#34;Stepping back&#34;&#xA;Update #4 on &#34;Stepping back&#34;&#xA;Final entry: Update #5 on &#34;Stepping back&#34;&#xA;&#xA;---&#xA;&#xA;Have you seen Paddington 2? I realise I&#39;m a little late to that particular movie, but it really is a delight. The whole production nails the tone perfectly, and never wavers. It would be so easy to drop an overly large knowing wink to the parents in the audience and risk breaking the spell for the kids, but they never do. They&#39;ve constructed a world on film that works exactly how I imagine an 8 year old thinks the world works, and it&#39;s marvellous.&#xA;&#xA;However, you&#39;re probably not here for the one paragraph film reviews, so, onward. In Update #2 on &#34;Stepping back&#34; I alleged that some of the public statements by the Tusky project, prompted by Stepping back from the Tusky project, were lies.&#xA;&#xA;It is my responsibility to present evidence for that. This is one of a collection of posts that do that, or otherwise respond to the public statement by the Tusky team.&#xA;&#xA;And if elzoido is reading, this one is dedicated to you. Only 48,567 words missing.&#xA;&#xA;The &#34;Admin Changes &amp; Transitions&#34; section&#xA;&#xA;People stepping down&#xA;&#xA;  In June 2023, first Maloki, then Conny stepped down from the project.&#xA;&#xA;This is partially false. Conny stepped down, Maloki did not, but planned to by end of the year.&#xA;&#xA;This is confirmed by the project update posted to Some changes going forward - Open Collective (2023-07-28) which says:&#xA;&#xA;  As it stands right now, Conny is resigning entirely from working on Tusky, and maloki is still on in an advisory position and as an admin until the end of the year.&#xA;&#xA;In July and August Maloki was still:&#xA;&#xA;Managing access to the GitHub repository&#xA;&#x9;I know this, because I contacted all the recent contributors to confirm their GitHub usernames, and forwarded them to Maloki to be added to the repository.&#xA;Attending Tusky team meetings (she did not attend the 2023-08-15 meeting, as she was unwell)&#xA;Providing feedback on how those meetings were scheduled&#xA;&#xA;That&#39;s all consistent with someone who is winding down their responsibilities and hasn&#39;t transferred all of them yet.&#xA;&#xA;She also said (in the Tusky Contributors channel, 2023-08-17, 15:12)&#xA;&#xA;  And honestly atm, I&#39;m contributing about the same amount as I always have. 😅 Minus the stress from feeling I should be doing more. 🤷‍♀️&#xA;&#xA;After the meeting, when I posted some initial results from my research in to possible legal structures for the project, Maloki was the only project member who responded, saying (2023-08-21): &#xA;&#xA;  I think you can gather up relevant information. If you feel like it.&#xA;    I think part of the problem is often that we don&#39;t have anyone with time or energy to look into these kind of things, so it&#39;s good to at least have the research&#xA;&#xA;Finally, the project had three Open Collective financial admins, Conny, Maloki, and Tak.&#xA;&#xA;When I asked the initial question, and through the remainder of the discussion, Maloki was the only who replied.&#xA;&#xA;I did not expect a reply from Conny, he had already stepped down. I was not surprised to see replies from Maloki, as I have explained, my understanding was that she was still engaged with aspects of the project. I am surprised that there was no reply from Tak.&#xA;&#xA;To summarise; Maloki had definitely announced an intention to step back. She may have been in the process of stepping back.&#xA;&#xA;But to say she had &#34;stepped down from the project&#34; is a lie.&#xA;Transitioning responsibilities&#xA;&#xA;  Conny&#39;s tasks, such as releases, were handed off to Nik; Maloki&#39;s tasks were split between Nik and Andi Mcc because they volunteered. &#xA;&#xA;Partially true, but misleading. The release process &#34;hand off&#34; went like this:&#xA;&#xA;  Connyduck: - Who wants to be responsible for the next release and follow our release process? https://github.com/tuskyapp/Tusky/blob/develop/Release.md @nikclayton I think you were interested?&#xA;  Nik: Happy to. My schedule for the next couple of weeks is reasonably free, so I&#39;ve got the time.&#xA;&#xA;(&#34;couple of weeks&#34; turned out to be woeful underestimate on my part. The 22.0 release was rocky, but eventually successful, in no small part thanks to a handful of users who were happy to try out some test builds while I found and fixed some longstanding account corruption bugs. If you used Tusky with multiple accounts and sometimes discovered that posts from account A were showing up from account B, or you thought you were posting from account A but you were actually posting from account B, they&#39;re fixed, you&#39;re welcome.)&#xA;&#xA;I was also, like some other contributors, given access to the Tusky repository so that I could approve and merge PRs from other contributors. This happened in late April 2023, long before Conny announced that he would be stepping down, and definitely not as part of any handoff.&#xA;&#xA;I can&#39;t think of any other of his responsibilities that were handed off only to me, formally or informally. I am happy to be corrected on this point.&#xA;&#xA;Collectively, we did add more people to the GitHub organisation so that they could help manage the queue of issues (e.g., closing them), or be added as reviewers to PRs.&#xA;&#xA;I believe &#34;Maloki&#39;s tasks were split between Nik and Andi Mcc because they volunteered&#34; is partially incorrect. I didn&#39;t explicitly volunteer to pick up any of Maloki&#39;s responsibilities, and was never asked to.&#xA;&#xA;This might be a reference to the fact that as part of managing the 22.0 release I was given the password to the @tusky@mastodon.social account so I could post information about the new beta versions and the final releases there, and respond to questions from testers.&#xA;&#xA;That was part of the release process work, it certainly wasn&#39;t part of formally picking up any of Maloki&#39;s responsibilties.&#xA;&#xA;The entirety of that discussion with Maloki (2023-04-26, well before any suggestion that she was stepping down, and so part of the period when posting release announcements could reasonably be expected to be part of her role) was:&#xA;&#xA;  Nik: Hi - do you want to post the 22-beta.1 announcement from the @tusky account, or ship the credentials to me and I&#39;ll do it?&#xA;  Maloki: Talk with Conny about that.&#xA;&#xA;Again, this was before Conny had announced his decision to step down. And as noted earlier, there were some tasks (like adding new users to the GitHub repository) that I couldn&#39;t do, and asked Maloki to do on my behalf.&#xA;&#xA;I can&#39;t speak to whatever specific responsibilities Andi picked up, except to note she definitely took over responsibility for organising and chairing the team meetings, and did so admirably.&#xA;&#xA;A legal entity&#xA;&#xA;The next three paragraphs:&#xA;&#xA;  As we tried to adjust...&#xA;  [...]&#xA;  At our August 15, 2023 contributor meeting...&#xA;  [...]&#xA;  In line with the responsibilities he&#39;d been given...&#xA;&#xA;Are broadly accurate, but also omit some colour that I think is important.&#xA;&#xA;First, the need for a formal legal entity for the project was not first broached at the August 15th meeting.&#xA;&#xA;This was first discussed in the team meeting of 2023-05-09, over three months earlier, as part of discussing the draft expense policy. The conclusion was to take no action at that time, but keep the idea in mind.&#xA;&#xA;10 days before the August 15th meeting, after Conny had announced he was stepping back, I collated my thoughts in to Open infrastructure problems, shared it with the &#34;Tusky Contributors&#34; channel, asked for feedback ahead of the meeting, and added it to the agenda so we had an opportunity to make an informed decision on next steps.&#xA;&#xA;Second, &#34;assigned the task&#34; and &#34;responsibilities he&#39;d been given&#34; suggests a considerably weightier process than actually happened. During the meeting I volunteered to contact SFC and other organisations, as they had already come up in my research, and no one objected / wanted to do the work themselves.&#xA;&#xA;Being added to the OpenCollective account&#xA;&#xA;  Around this same time, Nik was given member access to our OpenCollective account, with the intent of admin status being transitioned to him down the line.&#xA;&#xA;For the record, I have no recollection of ever being told about this, asked if I wanted the responsibility, or given the opportunity to decline.&#xA;&#xA;I have searched through discussion archives and private messages, and can find no reference to it.&#xA;&#xA;If I have missed one I am happy to be corrected, but this statement from the project is the first time I am aware of this.&#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>Edit to add this set of links to the posts in the series</p>
<ul><li><a href="https://write.as/nikclayton/stepping-back-from-the-tusky-project" rel="nofollow">Stepping back from the Tusky project</a></li>
<li><a href="https://write.as/nikclayton/update-on-1-stepping-back" rel="nofollow">Update #1 on “Stepping back”</a></li>
<li><a href="https://write.as/nikclayton/update-2-on-stepping-back" rel="nofollow">Update #2 on “Stepping back”</a></li>
<li><a href="https://write.as/nikclayton/update-3-on-stepping-back" rel="nofollow">Update #3 on “Stepping back”</a></li>
<li><a href="https://write.as/nikclayton/update-4-on-stepping-back" rel="nofollow">Update #4 on “Stepping back”</a></li>
<li>Final entry: <a href="https://write.as/nikclayton/update-5-on-stepping-back" rel="nofollow">Update #5 on “Stepping back”</a></li></ul>

<hr/>

<p>Have you seen Paddington 2? I realise I&#39;m a little late to that particular movie, but it really is a delight. The whole production nails the tone perfectly, and never wavers. It would be so easy to drop an overly large knowing wink to the parents in the audience and risk breaking the spell for the kids, but they never do. They&#39;ve constructed a world on film that works exactly how I imagine an 8 year old thinks the world works, and it&#39;s marvellous.</p>

<p>However, you&#39;re probably not here for the one paragraph film reviews, so, onward. In <a href="https://write.as/nikclayton/update-2-on-stepping-back" rel="nofollow">Update #2 on “Stepping back”</a> I alleged that some of the public statements by the Tusky project, prompted by <a href="https://write.as/nikclayton/stepping-back-from-the-tusky-project" rel="nofollow">Stepping back from the Tusky project</a>, were lies.</p>

<p>It is my responsibility to present evidence for that. This is one of a collection of posts that do that, or otherwise respond to the public statement by the Tusky team.</p>

<p>And if <code>elzoido</code> is reading, this one is dedicated to you. Only 48,567 words missing.</p>

<h2 id="the-admin-changes-transitions-section" id="the-admin-changes-transitions-section">The “Admin Changes &amp; Transitions” section</h2>

<h3 id="people-stepping-down" id="people-stepping-down">People stepping down</h3>

<blockquote><p>In June 2023, first Maloki, then Conny stepped down from the project.</p></blockquote>

<p>This is partially false. Conny stepped down, Maloki did not, but planned to by end of the year.</p>

<p>This is confirmed by the project update posted to <a href="https://opencollective.com/tusky/updates/some-changes-going-forward" rel="nofollow">Some changes going forward – Open Collective</a> (2023-07-28) which says:</p>

<blockquote><p>As it stands right now, Conny is resigning entirely from working on Tusky, and maloki is still on in an advisory position and as an admin until the end of the year.</p></blockquote>

<p>In July and August Maloki was still:</p>
<ul><li>Managing access to the GitHub repository
<ul><li>I know this, because I contacted all the recent contributors to confirm their GitHub usernames, and forwarded them to Maloki to be added to the repository.</li></ul></li>
<li>Attending Tusky team meetings (she did not attend the 2023-08-15 meeting, as she was unwell)</li>
<li>Providing feedback on how those meetings were scheduled</li></ul>

<p>That&#39;s all consistent with someone who is winding down their responsibilities and hasn&#39;t transferred all of them yet.</p>

<p>She also said (in the Tusky Contributors channel, 2023-08-17, 15:12)</p>

<blockquote><p>And honestly atm, I&#39;m contributing about the same amount as I always have. 😅 Minus the stress from feeling I should be doing more. 🤷‍♀️</p></blockquote>

<p>After the meeting, when I posted some initial results from my research in to possible legal structures for the project, Maloki was the only project member who responded, saying (2023-08-21):</p>

<blockquote><p>I think you can gather up relevant information. If you feel like it.</p>

<p>I think part of the problem is often that we don&#39;t have anyone with time or energy to look into these kind of things, so it&#39;s good to at least have the research</p></blockquote>

<p>Finally, the project had three Open Collective financial admins, Conny, Maloki, and Tak.</p>

<p>When I asked the initial question, and through the remainder of the discussion, Maloki was the only who replied.</p>

<p>I did not expect a reply from Conny, he had already stepped down. I was not surprised to see replies from Maloki, as I have explained, my understanding was that she was still engaged with aspects of the project. I am surprised that there was no reply from Tak.</p>

<p>To summarise; Maloki had definitely announced an intention to step back. She may have been in the process of stepping back.</p>

<p>But to say she had “stepped down from the project” is a lie.</p>

<h3 id="transitioning-responsibilities" id="transitioning-responsibilities">Transitioning responsibilities</h3>

<blockquote><p>Conny&#39;s tasks, such as releases, were handed off to Nik; Maloki&#39;s tasks were split between Nik and Andi Mcc because they volunteered. </p></blockquote>

<p>Partially true, but misleading. The release process “hand off” went like this:</p>

<blockquote><p><strong>Connyduck</strong>: – Who wants to be responsible for the next release and follow our release process? <a href="https://github.com/tuskyapp/Tusky/blob/develop/Release.md" rel="nofollow">https://github.com/tuskyapp/Tusky/blob/develop/Release.md</a> @nikclayton I think you were interested?
<strong>Nik</strong>: Happy to. My schedule for the next couple of weeks is reasonably free, so I&#39;ve got the time.</p></blockquote>

<p>(“couple of weeks” turned out to be woeful underestimate on my part. The 22.0 release was rocky, but eventually successful, in no small part thanks to a handful of users who were happy to try out some test builds while I found and fixed some longstanding account corruption bugs. If you used Tusky with multiple accounts and sometimes discovered that posts from account A were showing up from account B, or you thought you were posting from account A but you were actually posting from account B, they&#39;re fixed, you&#39;re welcome.)</p>

<p>I was also, like some other contributors, given access to the Tusky repository so that I could approve and merge PRs from other contributors. This happened in late April 2023, long before Conny announced that he would be stepping down, and definitely not as part of any handoff.</p>

<p>I can&#39;t think of any other of his responsibilities that were handed off only to me, formally or informally. I am happy to be corrected on this point.</p>

<p>Collectively, we did add more people to the GitHub organisation so that they could help manage the queue of issues (e.g., closing them), or be added as reviewers to PRs.</p>

<p>I believe “<em>Maloki&#39;s tasks were split between Nik and Andi Mcc because they volunteered</em>” is partially incorrect. I didn&#39;t explicitly volunteer to pick up any of Maloki&#39;s responsibilities, and was never asked to.</p>

<p>This might be a reference to the fact that as part of managing the 22.0 release I was given the password to the <a href="/@/tusky@mastodon.social" class="u-url mention" rel="nofollow">@<span>tusky@mastodon.social</span></a> account so I could post information about the new beta versions and the final releases there, and respond to questions from testers.</p>

<p>That was part of the release process work, it certainly wasn&#39;t part of formally picking up any of Maloki&#39;s responsibilties.</p>

<p>The entirety of that discussion with Maloki (2023-04-26, well before any suggestion that she was stepping down, and so part of the period when posting release announcements could reasonably be expected to be part of her role) was:</p>

<blockquote><p><strong>Nik</strong>: Hi – do you want to post the 22-beta.1 announcement from the @tusky account, or ship the credentials to me and I&#39;ll do it?
<strong>Maloki</strong>: Talk with Conny about that.</p></blockquote>

<p>Again, this was before Conny had announced his decision to step down. And as noted earlier, there were some tasks (like adding new users to the GitHub repository) that I couldn&#39;t do, and asked Maloki to do on my behalf.</p>

<p>I can&#39;t speak to whatever specific responsibilities Andi picked up, except to note she definitely took over responsibility for organising and chairing the team meetings, and did so admirably.</p>

<h3 id="a-legal-entity" id="a-legal-entity">A legal entity</h3>

<p>The next three paragraphs:</p>

<blockquote><p>As we tried to adjust...
[...]
At our August 15, 2023 contributor meeting...
[...]
In line with the responsibilities he&#39;d been given...</p></blockquote>

<p>Are broadly accurate, but also omit some colour that I think is important.</p>

<p>First, the need for a formal legal entity for the project was <strong>not</strong> first broached at the August 15th meeting.</p>

<p>This was first discussed in the team meeting of 2023-05-09, over three months earlier, as part of discussing the draft expense policy. The conclusion was to take no action at that time, but keep the idea in mind.</p>

<p>10 days before the August 15th meeting, after Conny had announced he was stepping back, I collated my thoughts in to <a href="https://cryptpad.fr/pad/#/2/pad/view/MHEKdKNoJn5yy4dux1fw9fE0J9TvdHJrxcuQmHVHPvY/" rel="nofollow">Open infrastructure problems</a>, shared it with the “Tusky Contributors” channel, asked for feedback ahead of the meeting, and added it to the agenda so we had an opportunity to make an informed decision on next steps.</p>

<p>Second, “assigned the task” and “responsibilities he&#39;d been given” suggests a considerably weightier process than actually happened. During the meeting I volunteered to contact SFC and other organisations, as they had already come up in my research, and no one objected / wanted to do the work themselves.</p>

<h3 id="being-added-to-the-opencollective-account" id="being-added-to-the-opencollective-account">Being added to the OpenCollective account</h3>

<blockquote><p>Around this same time, Nik was given member access to our OpenCollective account, with the intent of admin status being transitioned to him down the line.</p></blockquote>

<p>For the record, I have no recollection of ever being told about this, asked if I wanted the responsibility, or given the opportunity to decline.</p>

<p>I have searched through discussion archives and private messages, and can find no reference to it.</p>

<p>If I have missed one I am happy to be corrected, but this statement from the project is the first time I am aware of this.</p>
]]></content:encoded>
      <guid>https://nikclayton.writeas.com/update-4-on-stepping-back</guid>
      <pubDate>Thu, 31 Aug 2023 22:29:12 +0000</pubDate>
    </item>
    <item>
      <title>Update #3 on &#34;Stepping back&#34;</title>
      <link>https://nikclayton.writeas.com/update-3-on-stepping-back?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Edit to add this set of links to the posts in the series&#xA;&#xA;Stepping back from the Tusky project&#xA;Update #1 on &#34;Stepping back&#34;&#xA;Update #2 on &#34;Stepping back&#34;&#xA;Update #3 on &#34;Stepping back&#34;&#xA;Update #4 on &#34;Stepping back&#34;&#xA;Final entry: Update #5 on &#34;Stepping back&#34;&#xA;&#xA;---&#xA;&#xA;In Update #2 on &#34;Stepping back&#34; I alleged that some of the public statements by the Tusky project, prompted by Stepping back from the Tusky project, were lies.&#xA;&#xA;It is my responsibility to present evidence for that. This is one of a collection of posts that do that, or otherwise respond to the public statement by the Tusky team.&#xA;&#xA;Oh, and if you&#39;re reading this and thinking &#34;Good God, is he really going to go through the Tusky statement sentence by sentence&#34;, no, I&#39;m not. It&#39;s just unfortunate that the first two are sufficiently misleading that they demand an individual r