<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Contributing-Factors</title>
<link>https://harrad.org/</link>
<atom:link href="https://harrad.org/index.xml" rel="self" type="application/rss+xml"/>
<description>Ecletic explorations of data, process and fixing problems</description>
<generator>quarto-1.10.18</generator>
<lastBuildDate>Tue, 15 Sep 2026 23:00:00 GMT</lastBuildDate>
<item>
  <title>Creating an LLM input bundle for my fellow directors</title>
  <dc:creator>Peter Harrad</dc:creator>
  <link>https://harrad.org/posts/2026/09/DirectorLLMInputs/Index.html</link>
  <description><![CDATA[ 





<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>I suppose it was inevitable; having won our block’s <a href="https://peterharrad.github.io/Contributing-Factors/posts/2026/08/RH-RTMEffort/">RTM effort</a>, multiple leaseholders contacted me to ask if they still needed to pay their service charge demand from the outgoing agent in full. Now, I know the lease pretty well, but decided to test the question on a few LLMs into which I’d fed the lease. I was horrified to get numerous answers on the question that were just plain wrong. Pointing the LLM in question to the clause that they’d ignored usually provoked a correction (not always), but this convinced me of the need to enable more accurate querying and analysis of the lease and other important documents - for me and for my fellow directors. So this blog outlines my journey of transforming a bunch of mostly scanned PDFs into a fully structured resource with tagging.</p>
<p>Key findings: - the major human value-add is understanding the macro structure of documents. AI is great at repeating tasks at scale, the holistic picture is something it struggles with - parallel to this is careful consideration on what to include - some information is just not appropriate to ingest - defining the guardrails in the instructions is critical. Having a set of test scenarios to iterate with ahead of time is how you check that they are working</p>
</section>
<section id="choosing-the-design" class="level2">
<h2 class="anchored" data-anchor-id="choosing-the-design">Choosing the design</h2>
<p>The first consideration was how to distribute the documents. At some point I’ll look into creating a full vector store and frontend, but initial investigations showed that this could easily turn into a very enjoyable and time-consuming diversion from more useful activities. So next I looked at ways to distribute it via a Claude Project or a Gemini Gem.</p>
<p>The initial idea was to generate a bundle of concept files in line with Google’s new Open Knowledge Format (OKF), that we could have the Project/Gem reference. But it turns out that input files have to be uploaded by hand in such cases - OKF really seems designed for exclusive use by agents. NotebookLM can look at a folder… but has no threaded conversations. Every option for providing an encapsulated solution had its own limitations.</p>
<p>So the eventual fallback was to provide single markdown files for each input document, albeit with each clause properly tagged using ideas borrowed from OKF. This gave me 10 files that I could share - within Gemini’s upload limit for gems. Then my colleagues could upload them into whatever tool they chose.</p>
</section>
<section id="what-to-ingest" class="level2">
<h2 class="anchored" data-anchor-id="what-to-ingest">What to ingest</h2>
<p>The next question was to select what information I should feed into this resource. The goal here is to provide an ongoing resource for directors to understand their responsibilities and options for taking action on various matters. This led to the following basic list of inputs:</p>
<ul>
<li>Contractual Documents and regulations - leases, service agreements, articles of association and codes of conduct</li>
<li>Title registers - records of property coupled with listings of relevant contractual agreements that touch the property</li>
<li>Relevant legislation - not the actual text of legislation, but links to the correct version</li>
<li>Instructions - instructions to the LLM on how to reason using the information (e.g.&nbsp;quote specific lease clauses)</li>
</ul>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://harrad.org/posts/2026/09/DirectorLLMInputs/BK122099.png" class="img-fluid figure-img"></p>
<figcaption>Not amenable to detailed spatial reasoning</figcaption>
</figure>
</div>
<p>I decided to exclude a few types of information.</p>
<p>First, documentation around building safety compliance - inspection results, regulations, and so on. Inspection results are transitory; the report comes, and remediations take place. Likewise, building regulations seem to be in constant flux at the moment, so since I did not want to adopt curating such information as an ongoing task, they had to be excluded from scope.</p>
<p>Second was spatial information such as maps and title plans. The idea is to allow directors to recieve accurate answers to their questions, and LLMs are currently limited in their spatial reasoning to support this. I decided to extract certain spatial information such as floor numbers for flats into a text file for accurate answers.</p>
<p>Last of all, it was tempting to provide information on the history of each flat and leaseholder as I’ve been in the block the longest and have had the most interaction with the other leaseholders. But brief reflection showed what a data protection nightmare this could become.</p>
</section>
<section id="cleaning-the-documents" class="level2">
<h2 class="anchored" data-anchor-id="cleaning-the-documents">Cleaning the documents</h2>
<p>Before I could start ingesting, the files themselves needed cleanup. For the leases, I had a number of scanned PDFs. Our services agreement and the RICS code of conduct werer proper PDFs with text, and the titles were also PDFs of text. I used Claude Code to clean the files, which worked - mostly. There were small errors here and there, important for a legal document, so this highlights the need to check the outputs in such cases.</p>
</section>
<section id="defining-the-document-ingestion---contracts-and-guidelines" class="level2">
<h2 class="anchored" data-anchor-id="defining-the-document-ingestion---contracts-and-guidelines">Defining the document ingestion - contracts and guidelines</h2>
<p>The largest group of documents - Contractual Documents and regulations - have a fairly standardised structure. The first section contain definitions of specific terms used in the document. The rest of the document is divided into chapters, sections, different documents call them differently but each contains a number of paragraphs that may have sub clauses.</p>
<div class="cell" data-layout-align="default">
<div class="cell-output-display">
<div>
<p></p><figure class="figure"><p></p>
<div>
<pre class="mermaid mermaid-js">%%{init: {'flowchart': {'rankSpacing': 90}}}%%
flowchart LR
  A[Document] --&gt; B[Definitions]
  A --&gt; C[Chapter]
  A --&gt; D[Chapter]
  A --&gt; E[Chapter]
  A --&gt; F[...]
  D --&gt; D1[Paragraph]
  D --&gt; D2[Paragraph]
  D --&gt; D3[Paragraph]
  D1 --&gt; D11[Sub-Paragraph]
  D1 --&gt; D12[Sub-Paragraph]
  D3 --&gt; D31[Sub-Paragraph]
  D3 --&gt; D32[Sub-Paragraph]
  D3 --&gt; D33[Sub-Paragraph]
</pre>
</div>
<p></p></figure><p></p>
</div>
</div>
</div>
<p>There was a concern over ingesting the lease - was it the same for each unit? As a check, I obtained someone else’s lease and checked it against my own. Apart from some fascinating (but trivial) discrepancies in the scanning, the language was identical - giving me the confidence that I could use my lease as the reference.</p>
</section>
<section id="defining-the-document-ingestion---titles" class="level2">
<h2 class="anchored" data-anchor-id="defining-the-document-ingestion---titles">Defining the document ingestion - titles</h2>
<p>Title registers are the other type of document to ingest, and they are also pretty standard in their structure.</p>
<ul>
<li>Each has three sections:
<ul>
<li>The property register lists the property and any transfers</li>
<li>The proprietorship register lists who owns what and any agreements that affect disposal</li>
<li>The charges register defines agreements that touch the property in question</li>
</ul></li>
</ul>
<p>Each section is a list of numbered and dated entries.</p>
<div class="cell" data-layout-align="default">
<div class="cell-output-display">
<div>
<p></p><figure class="figure"><p></p>
<div>
<pre class="mermaid mermaid-js">%%{init: {'flowchart': {'rankSpacing': 90}}}%%
flowchart LR
  A[Title Register] --&gt; B[A. Property register]
  A --&gt; C[B. Proprietorship register]
  A --&gt; D[C. Charges register]
  B --&gt; B1@{ shape: docs, label: "List of entries"}
  C --&gt; C1@{ shape: docs, label: "List of entries"}
  D --&gt; D1@{ shape: docs, label: "List of entries"}
</pre>
</div>
<p></p></figure><p></p>
</div>
</div>
</div>
<p>This one had me thinking for a long time. Arguably each separate entry is its own concept. But a given entry often does not give much information. For example:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Entry</th>
<th>Date</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>4</td>
<td>2002-06-18</td>
<td>An Agreement dated 2 May 2002 pursuant to Section 106 of the Town and Country Planning Act 1990 and Section 111 of the Local Government Act 1972 made between (1) Reading Borough Council and (2) Bewley Homes PLC supplemental to the Agreement dated 28 February 2000 referred to above contains provisions relating to the development of the land in this title and other land.<br>The said Deed also contains covenants.<br>NOTE: Copy filed under BK122099.</td>
</tr>
</tbody>
</table>
<p>This being the case, all that the AI could do is list an entry. I decided to treat each section as a concept for the purposes of OKF.</p>
</section>
<section id="defining-the-document-ingestion---legislation" class="level2">
<h2 class="anchored" data-anchor-id="defining-the-document-ingestion---legislation">Defining the document ingestion - Legislation</h2>
<p>In theory I could ingest various relevant legislation, but in practice the UK government is excellent at making legislation available online. For example, here is the <a href="https://www.legislation.gov.uk/ukpga/2002/15/part/2/chapter/1">legislation defining the right to manage</a>. The key thing to be wary of to use the current version of any act or statutory instrument, as they do get amended over time - the current template articles of association for an RTM company have gone through 4 iterations. The other caveat here then, is the need to be aware of freshness and provenance.</p>
<p>So, each piece of relevant legislation becomes a separate concept (and hence file) in the bundle, where we can track the link to the actual resource along with relevant metadata.</p>
</section>
<section id="defining-the-document-ingestion---the-instruction-file" class="level2">
<h2 class="anchored" data-anchor-id="defining-the-document-ingestion---the-instruction-file">Defining the document ingestion - the instruction file</h2>
<p>The last piece of the puzzle was the instruction file. Easy enough to create a first cut, but how to check operation? Here I defined half a dozen theoretical test questions, some based on queries that have already arisen, some theoretical. For example, could a leaseholder install <a href="https://www.bbc.co.uk/news/articles/c4g3y6398nwo">plugin solar panels</a> on their balcony?</p>
<p>Using these test cases, I was able to iterate on what instructions file would give the best result. The key points:</p>
<ul>
<li>It’s a search-and-citation aid, not a lawyer.</li>
<li>It answers only from the documents it’s given.</li>
<li>Every statement is cited.</li>
<li>It surfaces differences but doesn’t reconcile them.</li>
<li>It doesn’t draw conclusions the documents don’t.</li>
<li>Statute law is pointed to, not paraphrased.</li>
<li>It flags its known limits instead of answering past them.</li>
<li>Settled matters get written up.</li>
<li>The tone is plain, factual and brief.</li>
</ul>
</section>
<section id="creating-the-files" class="level2">
<h2 class="anchored" data-anchor-id="creating-the-files">Creating the files</h2>
<p>So with the document structure understood, what remained was the processing to generate the output files. To do this, I iterated on a processing prompt for each file, tweaking after each output run. For example, the prompt for the single-file individual lease is</p>
<pre><code>  _One file, 'sample-lease.md', of 140 sections: "Definitions" and "Particulars" (no reference), then each clause, sub-clause and general-words section with its clause
  number as its reference, clauses 3, 4 and 5 listing their sub-clause numbers too, then each schedule paragraph with its paragraph number. Parts B, C and E of the Sixth
  Schedule have no reference. Links such as "Clause 7.10" and "Paragraph 3 of the Seventh Schedule" point to '#clause-07-10' and '#schedule-seventh-03'._</code></pre>
<p>This illustrates the judgement required — clauses 3–5 keep their sub-clause numbers, these sections have no reference.</p>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>This effort took a lot longer than expected… but the largest part of it was to understand the structure of the documents and then embed that understanding in the config files. Now the directors and I have a much more useful set of documents that we can use as we take the block forward. It was also a good exploration of where AI is a force multiplier, and where it can be a trap.</p>
<p>Anonymised outputs and associated code are at https://github.com/peterharrad/RHDirectorAssistant</p>


</section>

 ]]></description>
  <category>using AI</category>
  <category>block management</category>
  <guid>https://harrad.org/posts/2026/09/DirectorLLMInputs/Index.html</guid>
  <pubDate>Tue, 15 Sep 2026 23:00:00 GMT</pubDate>
  <media:content url="https://harrad.org/posts/2026/09/DirectorLLMInputs/LegalDocStructure.png" medium="image" type="image/png" height="83" width="144"/>
</item>
<item>
  <title>A deep dive into service charge history</title>
  <dc:creator>Peter Harrad</dc:creator>
  <link>https://harrad.org/posts/2026/08/ServiceCharge-Analysis/Index.html</link>
  <description><![CDATA[ 





<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>As described in my <a href="https://peterharrad.github.io/Contributing-Factors/posts/2026/08/RH-RTMEffort/">previous post</a>, I spent most of H1 2026 leading a Right To Manage effort for my apartment block. Now we directors need to start understanding the service charge - the history, the components and the areas to be wary of. I’ve used tools like pandas and Jupyter notebooks before, but I thought it would be interesting to see how Claude Code would do on such a task. Supporting files are <a href="https://github.com/peterharrad/Service-Charge">here</a></p>
<p>The exploration was useful in giving areas for us to look at, but also exposed some intriguing pitfalls of using AI for this kind of work.</p>
<ul>
<li>Key points:
<ul>
<li>Don’t trust the AI to find the right data without guidance</li>
<li>An AI-written redaction script leaked the names it was redacting — in a comment, a variable name, and an array literal</li>
<li>Lexical analysis is vulnerable to repeated text and small corpora of text</li>
<li>Expect a single request to provide a lot of analysis - be wary of it pushing you in a particular direction</li>
<li>Jupyter throws lots of graphs at you, the Claude Code interface throws lots of commentary at you. So what you need should guide the tool</li>
</ul></li>
</ul>
</section>
<section id="getting-the-data" class="level2">
<h2 class="anchored" data-anchor-id="getting-the-data">Getting the Data</h2>
<p>I moved in 7 years ago, and had documents mostly covering that period. The first hiccup was that halfway through, our existing managing agent was bought by another company, with a different approach to presenting the accounts. The 2021 accounts were a bare ledger dump and there was no 2023 budget, so figures for those years come from the comparative columns of the following year’s accounts. The apparent change of agent is a rename rather than a handover — <a href="https://find-and-update.company-information.service.gov.uk/company/06805193">the same company throughout</a> — so the comparatives are the same organisation restating its own figures, not a successor reconstructing a predecessor’s. Where I could check a comparative against the original, the carry-over was exact. All in all, I had actuals for 2019-2025, and budgets for 2020 and 2022-2026. It felt like this was enough to start with. The accounts and budgets from 2024 also had commentaries, which opened the door to some extra analysis - to be discussed later.</p>
</section>
<section id="getting-the-financial-data" class="level2">
<h2 class="anchored" data-anchor-id="getting-the-financial-data">Getting the financial data</h2>
<p>The early accounts to 2022 were scanned images. To start, I simply instructed Claude to extract the P&amp;L for each year, from each file. Claude did an excellent job (zero transcription errors), but was most apologetic - explaining that the scanned files didn’t separate out P&amp;L into the different budget schedules that the block had. Which, on checking, turned out to be complete rubbish. Lesson - don’t just check the figures that AI brings you, check if it simply didn’t read far enough in the document. Fixed by rerunning the command but specifying the precise pages in the scanned document to look at.</p>
<p>The next issue was that the two sets of accounts had slightly different categories - e.g.&nbsp;the old one separated out insurance types, the new one aggregated them. Decision: the newer agent was the more pertinent data, so I had the AI aggregate the older data accordingly.</p>
<p>Lesson learned: check the data that AI extracts, but also check availability, despite what the AI tells you.</p>
</section>
<section id="cleansing-the-commentary" class="level2">
<h2 class="anchored" data-anchor-id="cleansing-the-commentary">Cleansing the commentary</h2>
<p>With a post like this, it’s natural that I might be expected to share the source data. Which means that I needed to be aware of confidentiality. In particular, where people’s names and contact details were shown, as well as specific quotes that contractors provided, these had to be redacted. There was also a question of whether anything in the commentary could be sensitive to the block itself.</p>
<p>So I had the AI create three scripts:</p>
<ul>
<li>redact_docx.py - a simple matching script to remove names and contact information. No reason to feed spammers.</li>
<li>score_sensitivity.py - a heuristic to score each line on potential sensitivity based on what it discussed and produce a file for me to inspect</li>
<li>sanitise_docx.py - a script to clean out any contractual figures and remove any lines that the sensitive line analysis had thrown up</li>
</ul>
<p>Simple enough, no? And if I hadn’t intended to share the scripts it would have been fine.</p>
<p>redact_docx.py helpfully listed the names and details for it to redact in the comments that had been generated at the top, and then listed the names in an array. Meanwhile, after I asked for sanitise_docx to remove a specific line that related to security, it had helpfully explained this removal in the comments and the code to do so was helpfully named in way that made it clear what information was being removed. Oops. So a couple of quick manual edits were in order. In practice, the time taken was probably equal to redacting the information manually… but this was useful learning for a future project that I’ll be writing about.</p>
<p>Lesson learned (or, rather, reinforced): Check the scripts that AI generates, not just the outputs. In retrospect, I should have explicitly told it to obfuscate the names of the relevant variables and functions.</p>
</section>
<section id="financial-analysis" class="level2">
<h2 class="anchored" data-anchor-id="financial-analysis">Financial Analysis</h2>
<p>Two questions stood out for me in the service charge - which areas had the greatest growth, and which areas showed the greatest variance of actual versus budget?</p>
<p>Asking about growth areas produced an impressive set of graphs, with two standing out as particularly useful. As shown below, general maintenance, electricity, and plant and machinery all stand out as significant items and topics that the directors need to dig into. It’s noticeable that reserve contributions are incredibly volatile - it seems like both agents used it as a smoothing function for the budget totals.</p>
<div id="fig-budgetgrowth" class="quarto-layout-panel">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-budgetgrowth-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="quarto-layout-row">
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://harrad.org/posts/2026/08/ServiceCharge-Analysis/BudgetGrowth.png" class="img-fluid figure-img"></p>
<figcaption>Heatmap of items</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://harrad.org/posts/2026/08/ServiceCharge-Analysis/chart-expenditure-by-category.png" class="img-fluid figure-img"></p>
<figcaption>Line item of key categories</figcaption>
</figure>
</div>
</div>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-budgetgrowth-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Two graphs showing the same culprits for service charge growth
</figcaption>
</figure>
</div>
<p>Variance tells a similar story. It seems clear that maintenance is not only one of the biggest contributors to service charge growth, but also one of the most unanticipated</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://harrad.org/posts/2026/08/ServiceCharge-Analysis/chart-bias-vs-volatility.png" class="img-fluid figure-img"></p>
<figcaption>Identifying the key areas of variance</figcaption>
</figure>
</div>
</section>
<section id="commentary-analysis" class="level2">
<h2 class="anchored" data-anchor-id="commentary-analysis">Commentary Analysis</h2>
<p>Likewise, there were two areas that interested me in the commentary. Specifically, did the commentaries tend to claim success or failure on specific topics, and did the language become more handwavy and evasive for the same topics. As an experiment, I decided to perform this via the Claude Code interface, not the Jupyter notebook.</p>
<p>For the analysis of claimed success and failure, the commentary is negative 6 times more often than it’s positive - perhaps understandable when trying to justify spiralling service charges. What’s more interesting is the topic breakdown: Insurance is the most consistently negative presentation, while energy costs are presented as a relative success.</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th style="text-align: left;">Topic</th>
<th style="text-align: right;">Paras</th>
<th style="text-align: right;">Optimism score</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">Insurance</td>
<td style="text-align: right;">10</td>
<td style="text-align: right;"><strong>-2.94</strong></td>
</tr>
<tr class="even">
<td style="text-align: left;">Reserve fund</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">-1.75</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Water &amp; pumps</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">-1.40</td>
</tr>
<tr class="even">
<td style="text-align: left;">Fire safety</td>
<td style="text-align: right;">22</td>
<td style="text-align: right;">-1.25</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Audit &amp; accounting</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;"><strong>+0.75</strong></td>
</tr>
<tr class="even">
<td style="text-align: left;">Electricity &amp; energy</td>
<td style="text-align: right;">19</td>
<td style="text-align: right;">+0.25</td>
</tr>
</tbody>
</table>
<p>More interesting was the evasive language analysis. A simple lexical analysis script produced the following, rather questionable results. Boilerplate and FAQ scored second in the list - and the top category only covered 58 words. Time for a rethink.</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th style="text-align: left;">Topic</th>
<th style="text-align: right;">Paragraphs</th>
<th style="text-align: right;">Words</th>
<th style="text-align: right;">Terms</th>
<th style="text-align: right;">Evasiveness</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">General maintenance</td>
<td style="text-align: right;">6</td>
<td style="text-align: right;">58</td>
<td style="text-align: right;">3</td>
<td style="text-align: right;">5.2</td>
</tr>
<tr class="even">
<td style="text-align: left;">Boilerplate FAQ</td>
<td style="text-align: right;">25</td>
<td style="text-align: right;">309</td>
<td style="text-align: right;">15</td>
<td style="text-align: right;">4.9</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Security &amp; access</td>
<td style="text-align: right;">4</td>
<td style="text-align: right;">155</td>
<td style="text-align: right;">7</td>
<td style="text-align: right;">4.5</td>
</tr>
<tr class="even">
<td style="text-align: left;">Major works</td>
<td style="text-align: right;">7</td>
<td style="text-align: right;">185</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">4.3</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Audit &amp; accounting</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">269</td>
<td style="text-align: right;">11</td>
<td style="text-align: right;">4.1</td>
</tr>
<tr class="even">
<td style="text-align: left;">Electricity &amp; energy</td>
<td style="text-align: right;">19</td>
<td style="text-align: right;">948</td>
<td style="text-align: right;">39</td>
<td style="text-align: right;">4.1</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Reserve fund</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">440</td>
<td style="text-align: right;">17</td>
<td style="text-align: right;">3.9</td>
</tr>
<tr class="even">
<td style="text-align: left;">Lifts</td>
<td style="text-align: right;">9</td>
<td style="text-align: right;">401</td>
<td style="text-align: right;">15</td>
<td style="text-align: right;">3.7</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Correspondence &amp; reassurance</td>
<td style="text-align: right;">28</td>
<td style="text-align: right;">604</td>
<td style="text-align: right;">22</td>
<td style="text-align: right;">3.6</td>
</tr>
<tr class="even">
<td style="text-align: left;">Fire safety</td>
<td style="text-align: right;">22</td>
<td style="text-align: right;">1,155</td>
<td style="text-align: right;">40</td>
<td style="text-align: right;">3.5</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Water &amp; pumps</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">243</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">3.3</td>
</tr>
<tr class="even">
<td style="text-align: left;">Insurance</td>
<td style="text-align: right;">10</td>
<td style="text-align: right;">572</td>
<td style="text-align: right;">18</td>
<td style="text-align: right;">3.1</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Car park &amp; undercroft</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">38</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">2.6</td>
</tr>
<tr class="even">
<td style="text-align: left;">Cleaning</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">246</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">2.0</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Grounds &amp; landscaping</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">102</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">2.0</td>
</tr>
<tr class="even">
<td style="text-align: left;">Management fee</td>
<td style="text-align: right;">4</td>
<td style="text-align: right;">58</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">1.7</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Service charge level</td>
<td style="text-align: right;">10</td>
<td style="text-align: right;">225</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">0.9</td>
</tr>
<tr class="even">
<td style="text-align: left;">Billing &amp; payment</td>
<td style="text-align: right;">23</td>
<td style="text-align: right;">1,344</td>
<td style="text-align: right;">11</td>
<td style="text-align: right;">0.8</td>
</tr>
</tbody>
</table>
<p>A quick examination showed that the boilerplate was repeated across all five files, biasing the result. Likewise, the single comment on general maintenance scores highly - but could just be due to chance.</p>
<p>Rebuilding the measure to deduplicate repeated text and drop thinly-populated topics moved boilerplate FAQ from second place to ninth, below almost every substantive topic — the original score was largely an artefact of the same standard passages recurring each year. On the cleaned figures electricity and energy tops the table at 3.8, with lifts and water and pumps also high; all of which show significant budget variance in the financial analysis. General maintenance and major works disappear from the analysis, which in some ways is telling - large areas of spend were simply skirted over.</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th style="text-align: left;">Topic</th>
<th style="text-align: right;">Paragraphs</th>
<th style="text-align: right;">Words</th>
<th style="text-align: right;">Terms</th>
<th style="text-align: right;">Evasiveness</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">Electricity &amp; energy</td>
<td style="text-align: right;">17</td>
<td style="text-align: right;">869</td>
<td style="text-align: right;">33</td>
<td style="text-align: right;">3.8</td>
</tr>
<tr class="even">
<td style="text-align: left;">Correspondence &amp; reassurance</td>
<td style="text-align: right;">14</td>
<td style="text-align: right;">332</td>
<td style="text-align: right;">12</td>
<td style="text-align: right;">3.6</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Lifts</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">358</td>
<td style="text-align: right;">13</td>
<td style="text-align: right;">3.6</td>
</tr>
<tr class="even">
<td style="text-align: left;">Fire safety</td>
<td style="text-align: right;">17</td>
<td style="text-align: right;">909</td>
<td style="text-align: right;">31</td>
<td style="text-align: right;">3.4</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Water &amp; pumps</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">243</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">3.3</td>
</tr>
<tr class="even">
<td style="text-align: left;">Billing &amp; payment</td>
<td style="text-align: right;">4</td>
<td style="text-align: right;">190</td>
<td style="text-align: right;">6</td>
<td style="text-align: right;">3.2</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Reserve fund</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">254</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">3.1</td>
</tr>
<tr class="even">
<td style="text-align: left;">Insurance</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">308</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">2.6</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Boilerplate FAQ</td>
<td style="text-align: right;">12</td>
<td style="text-align: right;">699</td>
<td style="text-align: right;">16</td>
<td style="text-align: right;">2.3</td>
</tr>
<tr class="even">
<td style="text-align: left;">Cleaning</td>
<td style="text-align: right;">4</td>
<td style="text-align: right;">211</td>
<td style="text-align: right;">4</td>
<td style="text-align: right;">1.9</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Unclassified</td>
<td style="text-align: right;">19</td>
<td style="text-align: right;">171</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.6</td>
</tr>
</tbody>
</table>
</section>
<section id="conclusions" class="level2">
<h2 class="anchored" data-anchor-id="conclusions">Conclusions</h2>
<p>The analysis has highlighted some important areas for us to focus on. We need to dig into the electricity and understand what’s driving the growth and unpredictability. The repeated unexpected variance in maintenance highlights that an attempt to understand expected lifetimes of different systems is long overdue.</p>
<p>Some other useful lessons fall out for future analysis using these tools.</p>
<p>It’s often said that you should treat AI like an intern whose work needs to be thoroughly checked. Two examples came up in this effort. The AI did an excellent job at extracting data from the image files… yet needed to be told which page to look at. At the same time, the redaction scripts smoothly removed sensitive data - while exposing it in the source code. I’ve read that models are trained to write clear, self-documenting code — but this pushes in the opposite direction to confidentiality.</p>
<p>A more subtle point is the initial problems with the evasive language. What could be a useful metric was initially badly biased due to repeated text and small sample size.</p>
<p>A fourth point stands out - the tendency of Claude Code to attempt to use its initiative. Ask for a matrix of evasive words in the commentary by topic, and you get an entire essay opining on the results. Ask the Jupyter notebook to analyse variance of budget v actual, and get a swathe of tables and graphs. Not a problem, but a subtle trap to be wary of when using AI for this kind of work - the specific outputs can end up guiding you down a path instead of you guiding the outputs. Last of all, while this happens whether working via the Jupyter notebook or the Claude Code interface, it manifests in different ways due to the different constraints of the two interfaces. The Jupyter notebook throws a bunch of tables and graphs at you, while the Claude Code interface waxes lyrical with commentary.</p>


</section>

 ]]></description>
  <category>data analysis</category>
  <category>using AI</category>
  <category>block management</category>
  <guid>https://harrad.org/posts/2026/08/ServiceCharge-Analysis/Index.html</guid>
  <pubDate>Fri, 28 Aug 2026 23:00:00 GMT</pubDate>
  <media:content url="https://harrad.org/posts/2026/08/ServiceCharge-Analysis/chart-bias-vs-volatility.png" medium="image" type="image/png" height="101" width="144"/>
</item>
<item>
  <title>Right To Manage - business transformation at my apartment block</title>
  <dc:creator>Peter Harrad</dc:creator>
  <link>https://harrad.org/posts/2026/08/RH-RTMEffort/</link>
  <description><![CDATA[ 





<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>Harry Scoffin, the founder of Free Leaseholders, recently told a <a href="https://www.youtube.com/watch?v=-6nLK1Kwj6w">Housing Committee hearing</a> that getting 50% of leaseholders in a large buy-to-let block to agree on anything is almost impossible. We got 86%, with nobody against. So I wanted to share how I rallied a coalition of mostly absentee landlords to exceed this figure so clearly, to take control of the block and rescue my equity - and how doing so ended up using a lot of the skills from past roles in presales and business transformation.</p>
<p>Late last year, I discovered that my apartment would be almost unsellable, as it was now one of the <a href="https://thenegotiator.co.uk/news/regulation-law-news/a-third-of-flats-may-be-unsellable-in-latest-housing-crisis/">estimated 37% of flats</a> in the UK whose service charge now exceeds 1% of the property’s value — the point at which lenders start refusing mortgages. When leaseholders of such properties have to sell, they are forced to sell at cash auction for a substantial discount. This was unacceptable.</p>
<p>So I decided to rally the other leaseholders to obtain Right to Manage - the legal right of a block of flats in this country to demand control of the management of the block. I had to forge a group of mostly remote leaseholders (some with a level of adversarial history) into a unified community, and keep it together while navigating a complex regulatory framework with a counterparty that had an inbuilt incentive to resist our efforts.</p>
</section>
<section id="building-the-base-of-support" class="level2">
<h2 class="anchored" data-anchor-id="building-the-base-of-support">Building the base of support</h2>
<p>We needed the support of 39 units - at least 50% of the block had to be members of the RTM Company before we could claim. The immediate problem that we faced, was how to contact and get in touch with a group of leaseholders who did not live in the block, and whose contact details were unknown. From the start I decided against asking the incumbent managing agent - there was essentially no chance that they would help, and tipping them off might cause them to start their own campaign to undermine ours. To start with, I used my existing network. There was already a small community of resident leaseholders held together via an email group and a WhatsApp group. I’d personally managed to add several people to this community by actively engaging with unknown residents - purely because you never know when a connection might be mutually beneficial.</p>
<p>This gave us a starter group of 12 - with 39 needed and ideally up to a dozen more. My working assumption was to treat the remaining units as rented out. Now, one option for the next step might have been to download the titles for the remaining units, and write to the registered addresses.</p>
<p>I chose not to do this as the next step for several reasons:</p>
<ul>
<li>The title registers cost £7 a time</li>
<li>People often forget to update their contact details on title registers when they move, and a look at property sales data showed that the majority of the units had not changed hands in 20 years</li>
<li>Letters are common and what with junkmail, the inclination is to dismiss an unexpected letter - “how can I get rid of this?”. A mailshot, personally signed by another resident, stands out</li>
<li>Landlords are often in touch with their tenants and some even have cordial relations in place</li>
</ul>
<p>So instead, I chose to do a personal mailshot - printing out 65 leaflets to place in each mailbox.</p>
</section>
<section id="selling-with-the-mailshot" class="level2">
<h2 class="anchored" data-anchor-id="selling-with-the-mailshot">Selling with the mailshot</h2>
<p>The mailshot was essentially a sales pitch - as a tenant, why should you care, and why should your landlord care? In a case like this, you need a few carefully chosen talking points. Too many, and it feels like some hard-sell sales pitch on late night television. Too few, and you fail to persuade.</p>
<p>So I chose to make the following talking points:</p>
<ul>
<li>If you are a tenant, rising service charges put financial pressure on your landlord to raise rents. Meanwhile, problems external to the flat are not fixed, affecting your quality of life</li>
<li>If you are a landlord, the value of your investment is being slowly eaten away</li>
</ul>
<p>And on each leaflet was a request to pass on my contact details to the owner of the property.</p>
<p>65 leaflets went out; over the course of a month, 13 new contacts reached out and stated their support for the effort. With something like this, you have to accept that some people will be slow to respond.</p>
<p>25 supporters, 39 needed.</p>
</section>
<section id="moving-on-to-referrals" class="level2">
<h2 class="anchored" data-anchor-id="moving-on-to-referrals">Moving on to referrals</h2>
<p>Some people are natural connectors, and if you can convince them of your case, they will put you in touch with other potential supporters or sources of contacts. This effort proved no different. Two of the landlords had lists of other leaseholders from previous efforts to rally the community. 21 more supporters stated their support. 46 supporters with 39 needed. But ideally we wanted more.</p>
<p>Another leaseholder was in contact with the director of the lettings agent who handled most of the lettings in the block - passed my details, they called me and after I convinced them of the cause, they contacted all their landlords that I was not in touch with. 12 more supporters - 58 total, with 39 needed.</p>
<p>8 more were to join us over the coming months, but we had enough at this point.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://harrad.org/posts/2026/08/RH-RTMEffort/supporters-bars.png" class="img-fluid figure-img"></p>
<figcaption>Where the support actually came from</figcaption>
</figure>
</div>
</section>
<section id="establishing-stakeholder-credibility" class="level2">
<h2 class="anchored" data-anchor-id="establishing-stakeholder-credibility">Establishing stakeholder credibility</h2>
<p>At this point, we had commitments from enough leaseholders and questions of stakeholder management came to the fore. There were two specific groups to consider.</p>
<p>The first and most important stakeholder was the part-time caretaker. While not living on site, they knew a lot of what went on at the block, and it was only a matter of time before they heard about the effort and started questioning what it would mean for them. So I sat down with them and explained very carefully what we planned and how it would actually empower them. I took care to visit them regularly and update them on progress.</p>
<p>The second stakeholder management question was how to keep the support of the group of supporters that I’d rallied. For historical reasons, certain leaseholders were deeply suspicious of each other, and I needed to avoid being seen to take sides.</p>
<p>I foresaw two separate problems:</p>
<ul>
<li>Having gained support, I needed to keep it until the claim went in. In particular, I needed to build up trust for when it came time to join the company</li>
<li>They might be concerned that I was making decisions to benefit myself to their own detriment</li>
</ul>
<p>Each required its own separate strategy.</p>
<p>To keep people invested, I sent out regular email newsletters, explaining progress and what the next steps would be.</p>
<p>To avoid the suspicion of this being my one-man feathering of the nest, I established an advisory committee made up of volunteers to act as a sounding board, with its own separate email and WhatsApp groups.</p>
<p>This immediately provoked a challenge from a couple of leaseholders, who while unwilling to join this group felt that one who had would subvert the effort in order to reintroduce short-term letting in violation of the lease. I found myself spending significant time reassuring them that I was not inclined to allow this and in fact would have a statutory duty to enforce the lease provisions.</p>
</section>
<section id="calling-in-a-professional" class="level2">
<h2 class="anchored" data-anchor-id="calling-in-a-professional">Calling in a professional</h2>
<p>So now it was time to form the company and start the claim process. The RTM process is notoriously <a href="https://www.leaseholdknowledge.com/right-to-manage-or-right-to-endless-misery-in-the-courts/">full of pitfalls</a>, and if the freeholder or incumbent managing agent decides to challenge, working through the courts can take years. You have to invite all leaseholders to join the company; get a single thing wrong and the claim is invalid. You have to notify all parties, and if you get anything wrong, the claim is invalid. And then the freeholder can demand a mountain of background paperwork, and if there are any discrepancies or errors, the claim is invalid. With all these pitfalls, we felt it was necessary to engage advisors. There are a range of companies that will help you through the RTM process, charging a wide range of fees.</p>
<p>We considered the key factors; the desire to ensure success so that we could immediately start work on reducing the service charge, and the fact that service charges were already in the mid 4-figures for most leaseholders. Given these, we engaged Shula Rich, one of the most recognised names in RTM advice provision. A key decision criterion was her stated approach of merely amending claims that were rejected for trivial reasons and resubmitting. This significantly reduced the risk of needing a lengthy and expensive challenge at the First Tier Tribunal, the section of the courts that deals with such disputes.</p>
</section>
<section id="choosing-the-replacement" class="level2">
<h2 class="anchored" data-anchor-id="choosing-the-replacement">Choosing the replacement</h2>
<p>At the same time, we needed to choose a replacement managing agent. Some RTM efforts manage the block themselves, but for us, a 77-flat riverside block with 4 entrances and a caretaker needed a professional company.</p>
<p>We created an ITT and sent it to a number of candidate companies after a couple of review iterations with the advisory committee. We then had each member of the advisory committee score the companies across five weighted categories, creating a shortlist of three. Detailed examinations and follow up questions produced a front runner, who we eventually engaged to take over. As with our advisor, their stated experience in taking over from the incumbent was a key factor.</p>
</section>
<section id="the-outcome" class="level2">
<h2 class="anchored" data-anchor-id="the-outcome">The outcome</h2>
<p>The claim was posted on the 4th of June. What with a weekend, deemed delivery was the 9th of June. The RTM regulations stated that the counterparties had a month to respond, so once we factored in another weekend and some leeway, we agreed a cutoff for response of the 13th of July. Again driven by the RTM regulations, the handover can only happen a minimum of 3 months after the response deadline. I chose to move it from Tuesday to Wednesday (to leave two clear working days between the weekends), so - the 14th of October.</p>
<p>As expected, the freeholder immediately responded with a request for evidence - we had to hand over no less than 79 pages of documentation for them to pick through for discrepancies. On the 8th of July, the freeholder sent over their formal acceptance of the claim. Contrary to anecdote, they were highly professional at every step.</p>
<p>How much will the service charge come down by? We’ll know once we have the new budget in place, but the consensus is that RTM cuts charges from 10% to 30% or even much more. A highly comparable block has roughly half the service charge levels.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://harrad.org/posts/2026/08/RH-RTMEffort/status.png" class="img-fluid figure-img"></p>
<figcaption>The final tally of supporters, floor by floor. Green is a leaseholder in favour: 66 of 77, against the 39 required.</figcaption>
</figure>
</div>
</section>
<section id="what-i-wished-id-done" class="level2">
<h2 class="anchored" data-anchor-id="what-i-wished-id-done">What I wished I’d done</h2>
<p>I should have identified and recruited directors much earlier in the process. As it is, it sometimes feels like my fellow directors are only now finding their feet with the claim already accepted.</p>
<p>I also should have anticipated the tensions between certain leaseholders and worked to pre-handle them. The concerns raised could have been anticipated.</p>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>A presales or business transformation effort requires the ability to craft an argument, reach stakeholders, manage stakeholders and navigate process and regulatory landscapes. All of these came to play in this effort. Going from 12 initial supporters to 66 needed a combination of cold approach, and networking - but just as in business, referrals win out every time. Looking to prehandle stakeholder objections was the right call, even if I failed to anticipate a key one - at the very least, the patterns put in place brought enough credibility to ride out that objection. Identifying the right suppliers with a traceable set of decisions also built trust. Last of all, simply being able to comprehend the process and describe it intelligently meant that the necessary notices did not provoke panic when they landed in leaseholders’ mailboxes.</p>


</section>

 ]]></description>
  <category>persuasion</category>
  <category>stakeholder management</category>
  <category>block management</category>
  <category>regulatory</category>
  <guid>https://harrad.org/posts/2026/08/RH-RTMEffort/</guid>
  <pubDate>Sat, 22 Aug 2026 23:00:00 GMT</pubDate>
  <media:content url="https://harrad.org/posts/2026/08/RH-RTMEffort/supporters-bars.png" medium="image" type="image/png" height="74" width="144"/>
</item>
</channel>
</rss>
