<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>The Meta Level</title>
  <subtitle>Modelling, analysis and mathematical curiosity — notes, experiments and consultancy work by Tikam Bilanie.</subtitle>
  <link href="https://themetalevel.org/feed.xml" rel="self"/>
  <link href="https://themetalevel.org/"/>
  <updated>2026-08-13T00:00:00.000Z</updated>
  <id>https://themetalevel.org/</id>
  <author>
    <name>Tikam Bilanie</name>
  </author>
  <entry>
    <title>The background chapters</title>
    <link href="https://themetalevel.org/notes/background-chapters/"/>
    <updated>2026-08-13T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/background-chapters/</id>
    <summary>Forty-one working chapters behind the report — the water, the rock, the demand and the scheme, in the order they bind.</summary>
    <content type="html">&lt;p&gt;The report is a summary. These are the working chapters behind it —
one set per layer of the model, in the order the layers bind. They are
written for someone checking the arithmetic rather than reading for
pleasure, which is why they sit back here rather than in the listings.&lt;/p&gt;
&lt;p&gt;Every figure in them regenerates from raw Environment Agency, BGS and
Defra data.&lt;/p&gt;
&lt;h2&gt;The pipeline&lt;/h2&gt;
&lt;p&gt;How the layers fit together, and what regenerates what.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/pipeline/&quot;&gt;The pipeline&lt;/a&gt;&lt;/strong&gt; — How the layers fit together. One directory per layer; this ties them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/manifest-v1/&quot;&gt;V1 manifest — what reproduces, and what does not&lt;/a&gt;&lt;/strong&gt; — The state of the project at the end of the scheme-layer batch, 2026-08-11. Written to the same standard as archive/v0/MANIFEST.md: what is here, what reproduces, and what does not.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The water layer&lt;/h2&gt;
&lt;p&gt;Rainfall in, river flow out, and the water table underneath.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/water-layer/&quot;&gt;The water layer&lt;/a&gt;&lt;/strong&gt; — How water moves through this landscape before anybody builds anything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/runoff-model/&quot;&gt;The runoff model - and the split&lt;/a&gt;&lt;/strong&gt; — Generated by build_runoff_model.py. Two linear reservoirs in parallel off one split fraction, calibrated against FLOW (which closes a water balance) on the first 70% of each…&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/river-routing/&quot;&gt;River routing - flow at a point that is not a gauge&lt;/a&gt;&lt;/strong&gt; — Generated by build_river_routing.py. The chapter the scheme layer is blocked on: an intake is never at a gauge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/rhynes/&quot;&gt;The rhynes - the low-level watercourses&lt;/a&gt;&lt;/strong&gt; — Generated by build_rhynes.py. The drainage network of the Levels, which every previous dataset in this project left out.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/water-table/&quot;&gt;The water table&lt;/a&gt;&lt;/strong&gt; — Generated by build_water_table.py. Fitted so that saturated thickness stops being the full thickness of the rock.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/water-table-dynamics/&quot;&gt;Is the water table dynamic?&lt;/a&gt;&lt;/strong&gt; — Yes - and the static fit in water_table.md does not capture any of it. That fit reduced ~4,100 days of daily record per station to one mean. This goes back to the series.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/water-table-coupled/&quot;&gt;A rainfall-driven water table&lt;/a&gt;&lt;/strong&gt; — Generated by build_wt_coupled.py. Step 2 of next_steps.md, built on the same store the runoff model uses, with the signed-exchange departure agreed before building.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/water-table-coupled-aet-high/&quot;&gt;A rainfall-driven water table — high evapotranspiration&lt;/a&gt;&lt;/strong&gt; — Generated by build_wt_coupled.py. Step 2 of next_steps.md, built on the same store the runoff model uses, with the signed-exchange departure agreed before building.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/water-table-coupled-aet-low/&quot;&gt;A rainfall-driven water table — low evapotranspiration&lt;/a&gt;&lt;/strong&gt; — Generated by build_wt_coupled.py. Step 2 of next_steps.md, built on the same store the runoff model uses, with the signed-exchange departure agreed before building.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The aquifer layer&lt;/h2&gt;
&lt;p&gt;Which rock could hold water, how much, and how well it is known.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/aquifer-layer/&quot;&gt;The aquifer layer&lt;/a&gt;&lt;/strong&gt; — What the rock is, where it is, and how much water it can hold.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/rock-layers/&quot;&gt;Rock layers, drawn from the boreholes&lt;/a&gt;&lt;/strong&gt; — Generated by build_rock_layers.py. The polygons take no part in the drawing - they are scored against it below.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/layer-model/&quot;&gt;Layer model — two passes and a ledger&lt;/a&gt;&lt;/strong&gt; — Generated by build_layer_model.py. Pass 1 is the defensible model. Pass 2 is everything admitted on an assumption, and every assumption is in the ledger.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/borehole-data/&quot;&gt;Borehole data — what we hold and what we have read&lt;/a&gt;&lt;/strong&gt; — Supporting file for the aquifer write-up. Living document: updated as logs are read. Generated maps come from map_boreholes.py; the readings live in borehole_sections.py.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/aquifer-inventory/&quot;&gt;Located aquifer inventory&lt;/a&gt;&lt;/strong&gt; — Generated by inventory_aquifers.py. Every known aquifer body within 40 km of the site-screen box, with its location.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/aquifer-volumes/&quot;&gt;Depths, thicknesses and volumes&lt;/a&gt;&lt;/strong&gt; — Generated by build_aquifer_volumes.py. Every body in aquifer_inventory.md, sized - with the confidence of every cell carried through and the weakest one governing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/click-targets/&quot;&gt;Click targets&lt;/a&gt;&lt;/strong&gt; — Paste back whatever each popup gives — formation name, age, and the LEX code if the More Information page shows one. Even the name alone is enough.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/portfolio-screen/&quot;&gt;The portfolio re-screen&lt;/a&gt;&lt;/strong&gt; — Generated by screen_portfolio.py. Every unit we hold information on, re-tested against a LOWER bar - not ‘is this the MAR store’ but &#39;does this have any role in an integrated…&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/aquifer-mapping-status/&quot;&gt;Aquifer mapping - where we stand&lt;/a&gt;&lt;/strong&gt; — Generated by aquifer_mapping_status.py. Three sources, kept separate on purpose: where they disagree, the borehole wins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/aquifer-data-gaps/&quot;&gt;Data we cannot fetch ourselves — manual retrieval note&lt;/a&gt;&lt;/strong&gt; — For papers/aquifers. Ordered by likely impact on the model, highest first. Everything here was attempted programmatically and failed, or is not served by any open endpoint.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/aquifer-next-steps/&quot;&gt;Next steps — the modelling roadmap&lt;/a&gt;&lt;/strong&gt; — Distinct from data_gaps.md, which lists data we cannot fetch. This lists work to do, in the order it has to be done, and says what each step unblocks. Written 2026-08-11.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/aquifer-appendix-estimates/&quot;&gt;Appendix - estimates, and what they rest on&lt;/a&gt;&lt;/strong&gt; — Generated by estimate_aquifer_unknowns.py. Every number in the aquifer model that is not a measurement is listed here. Nothing below is hidden in a script.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The demand layer&lt;/h2&gt;
&lt;p&gt;What the water would be for, and why demand is not the constraint.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/demand-layer/&quot;&gt;The demand layer&lt;/a&gt;&lt;/strong&gt; — Who needs how much water, when, and what happens if they do not get it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/demand-data-sources/&quot;&gt;What demand data actually exists&lt;/a&gt;&lt;/strong&gt; — What was looked for, what was found, what was fetched, and what still needs asking for. First chapter of the demand layer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/licensed-abstraction/&quot;&gt;Licensed abstraction, scaled&lt;/a&gt;&lt;/strong&gt; — Generated by build_demand_abstraction.py. Replaces the blanket 3 Mm3/yr with a figure that has a source - and a stated weakness.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/demand-series/&quot;&gt;A demand series with a rhythm&lt;/a&gt;&lt;/strong&gt; — Generated by build_demand_series.py. Shape from physics, level from the licence.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The scheme layer&lt;/h2&gt;
&lt;p&gt;What you would build, and in what order you are allowed to decide it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/scheme-layer/&quot;&gt;The scheme layer&lt;/a&gt;&lt;/strong&gt; — What you would actually build, and in what order you are allowed to decide it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/availability/&quot;&gt;Availability - what the rivers will give up&lt;/a&gt;&lt;/strong&gt; — Generated by build_scheme_availability.py. First chapter of the scheme layer: the resource, before anything is built to catch it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/design-rule/&quot;&gt;The design rule, tested&lt;/a&gt;&lt;/strong&gt; — Generated by build_scheme_design.py.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/operating-concept/&quot;&gt;Fill fast, empty slow - does the concept hold?&lt;/a&gt;&lt;/strong&gt; — Generated by build_operating_concept.py.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/scheme-sizing/&quot;&gt;Sizing - what each scheme delivers when it is needed most&lt;/a&gt;&lt;/strong&gt; — Generated by build_scheme_sizing.py. A capability curve, not a recommendation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/scheme-options/&quot;&gt;Scheme options - realistic reservoirs, no reservoir, and several smaller ones&lt;/a&gt;&lt;/strong&gt; — Generated by build_scheme_options.py. The three follow-ups to sizing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/reconcile-portfolio/&quot;&gt;Reconciling the portfolio contradiction&lt;/a&gt;&lt;/strong&gt; — Generated by build_scheme_reconcile.py.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/pump-sizing/&quot;&gt;Pump sizing - how many units, and where&lt;/a&gt;&lt;/strong&gt; — Generated by build_pump_sizing.py. No model run: arithmetic on the divertible series.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/aquifer-operation/&quot;&gt;Aquifer operation - the capacitor&lt;/a&gt;&lt;/strong&gt; — Generated by build_scheme_aquifer.py. Second chapter of the scheme layer: what the ground can take, hold and give back.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/pairing-aquifers/&quot;&gt;Pairing aquifers - leakage as the delivery mechanism&lt;/a&gt;&lt;/strong&gt; — Generated by build_scheme_pairing.py.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/gravity-screen/&quot;&gt;The gravity screen - searching for what the old screen excluded&lt;/a&gt;&lt;/strong&gt; — Generated by build_gravity_screen.py.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/gravity-sites/&quot;&gt;Can any basin be filled by gravity?&lt;/a&gt;&lt;/strong&gt; — Generated by build_gravity_sites.py.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/drought-tests/&quot;&gt;Drought tests - today, and six years of it&lt;/a&gt;&lt;/strong&gt; — Generated by build_drought_tests.py.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/scheme-synthesis/&quot;&gt;Synthesis - three schemes, and the shape of the space&lt;/a&gt;&lt;/strong&gt; — Generated by build_scheme_synthesis.py. Closes the loop opened by availability.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;/notes/banking-winter-water/&quot;&gt;← Back to the report&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Banking winter water for a dry summer</title>
    <link href="https://themetalevel.org/notes/banking-winter-water/"/>
    <updated>2026-08-13T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/banking-winter-water/</id>
    <summary>Somerset has too much water in February and not enough in July. Can the surplus be caught and kept — in a reservoir, underground, or both — and given back when it is needed?</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;July 2026 has been the driest July in the seventeen-year record: 4.5 mm of rain against a July average of 57 mm&lt;/strong&gt;. That is the problem in one number.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;148&lt;/strong&gt; — million m³ a year could lawfully be taken at high flows&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;86%&lt;/strong&gt; — of it arrives between November and March&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;2%&lt;/strong&gt; — arrives in June, July and August, when it is wanted&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;9&lt;/strong&gt; — bursts a year, each lasting about two days&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The water exists&lt;/strong&gt; — many times more than any scheme here would use.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;It arrives in short bursts.&lt;/strong&gt; This, not the annual total, is what makes the engineering hard.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A reservoir alone cannot bridge a drought.&lt;/strong&gt; It empties every summer and refills every winter, so it carries nothing from one year to the next. Underground storage can — if the water stays put.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The most promising options are not the obvious ones:&lt;/strong&gt; a basin that fills itself by gravity, and flood-storage moors that already exist.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No scheme is being recommended here.&lt;/strong&gt; Nothing in this study is costed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;What changed since version 1&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Version 1 was circulated on 12 August. Five things have changed, and two of them are corrections rather than additions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A correction.&lt;/strong&gt; Version 1 quoted a 389-day half-life beside a 15.7 million m³ capacity. Both were right for their own well field — one for a 1 km radius, one for 2 km — and wrong together. Everything is now quoted for the same 2 km field. No model run changed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A correction.&lt;/strong&gt; Option E was described as pairing two different rocks. It was not: both its stores had the same rock and differed only in size. It has been rebuilt on two formations that really are different.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Every rock body now carries a leakage figure.&lt;/strong&gt; Version 1 left nine of fourteen blank. They are estimated from rock type and flagged as such — a blank read as “nothing is known”, which was not true.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An eighth option&lt;/strong&gt;, H: the same scheme as C on the best untested rock, to price what better ground is worth.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New maps and charts&lt;/strong&gt;: where each option would sit, what reaches the rivers, and how each scheme behaves through the year.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The ranking of the options is unchanged.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;The current situation&lt;/h2&gt;
&lt;p&gt;The Somerset Levels flood in winter and run short in summer. Both happen for the same reason: the ground is flat, the rivers are slow, and the water arrives when nobody wants it.&lt;/p&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/map_setting.jpg&quot; alt=&quot;Where the water is, and where the rock is. The dense blue mesh is the Levels’ drainage network — some 1,700 km of rhynes below 10 m above sea level. Red circles are the rock bodies that could store water; note that they sit on the western edge, away from the largest rivers.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Where the water is, and where the rock is.&lt;/strong&gt; The dense blue mesh is the Levels’ drainage network — some 1,700 km of rhynes below 10 m above sea level. Red circles are the rock bodies that could store water; note that they sit on the western edge, away from the largest rivers.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;86% of the water that could lawfully be taken arrives between November and March.&lt;/strong&gt; Only 2% arrives in June, July and August. Any scheme here is therefore a &lt;em&gt;battery&lt;/em&gt;, not a tap: its job is to move water across six months, not to find more of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In a drought year there is very little to catch.&lt;/strong&gt; The surplus is a winter thing — nearly all of it arrives between November and March — so a drought year here means a winter whose floods never came. In the worst year of the record only &lt;strong&gt;21% of the average&lt;/strong&gt; was available to take.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Water given out in a dry summer was caught the previous winter, or the one before that.&lt;/strong&gt; It cannot be topped up during the drought, because the drought &lt;em&gt;is&lt;/em&gt; the failure of the winter that would have filled it.&lt;/p&gt;
&lt;h3&gt;What limits a reservoir here&lt;/h3&gt;
&lt;p&gt;This is flat, low, soft ground with high land value and deep peat in places.&lt;/p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Assumption&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Much above &lt;strong&gt;5 million m³&lt;/strong&gt; is taken to be an unrealistic cell on this ground. That is a judgement, not a calculation. It matters, because to stop losing water over the spillway entirely you would need around 10 million m³ — so a reservoir here will always take a &lt;em&gt;share&lt;/em&gt; of the winter surplus.&lt;/p&gt;
&lt;/div&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/reservoirs.jpg&quot; alt=&quot;Eight places the ground is the right shape. Each is a bunded cell of roughly 5 million m³ sitting beside a river, with the pipe that would fill it shown dotted. This is a terrain screen and nothing more: it says the shape of the land works, not that the land is available, the peat is shallow enough, or anyone would sell it. What it does show is that the constraint is not finding one site — it is that no single site on this ground gets much past 5 million m³.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Eight places the ground is the right shape.&lt;/strong&gt; Each is a bunded cell of roughly 5 million m³ sitting beside a river, with the pipe that would fill it shown dotted. This is a &lt;em&gt;terrain&lt;/em&gt; screen and nothing more: it says the shape of the land works, not that the land is available, the peat is shallow enough, or anyone would sell it. What it does show is that the constraint is not finding one site — it is that no single site on this ground gets much past 5 million m³.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3&gt;What limits an aquifer&lt;/h3&gt;
&lt;p&gt;Water can also be put underground into porous rock and pumped back later. This is done elsewhere; the largest UK example supplies London. Underground storage does not evaporate and can hold water between years — but:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It leaks.&lt;/strong&gt; Water spreads away from where you put it. A 2 km well field in the local sandstone loses half of what is in it in about four years; a smaller field loses it faster, and the same rock can be either.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It is fullest when you want to fill it.&lt;/strong&gt; The water table peaks in February, exactly when the surplus arrives.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nothing in seventeen years of local records contains an injection.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/aquifers.jpg&quot; alt=&quot;Red holds water between years; brown hands it back within weeks. Hatching marks the ten bodies whose leakage is estimated from rock type rather than measured — which is most of the map, and is the honest state of the evidence. The three brown bodies are the fractured limestones: useless as a bank, and exactly what option E needs as a river feed.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Red holds water between years; brown hands it back within weeks.&lt;/strong&gt; Hatching marks the ten bodies whose leakage is estimated from rock type rather than measured — which is most of the map, and is the honest state of the evidence. The three brown bodies are the fractured limestones: useless as a bank, and exactly what option E needs as a river feed.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The table below is every body, with the same 2 km well field assumed on each so the rows can be compared.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Body&lt;/th&gt;
&lt;th&gt;Rock&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Distance to a river&lt;/th&gt;
&lt;th&gt;Half the water has spread away in&lt;/th&gt;
&lt;th&gt;What that well field holds&lt;/th&gt;
&lt;th&gt;Where the figures come from&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Upper Greensand Formation&lt;/td&gt;
&lt;td&gt;203 km²&lt;/td&gt;
&lt;td&gt;0.1 km&lt;/td&gt;
&lt;td&gt;6 years&lt;/td&gt;
&lt;td&gt;18.8 Mm³&lt;/td&gt;
&lt;td&gt;guessed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Helsby Sandstone Formation&lt;/td&gt;
&lt;td&gt;177 km²&lt;/td&gt;
&lt;td&gt;0.0 km&lt;/td&gt;
&lt;td&gt;4 years&lt;/td&gt;
&lt;td&gt;15.7 Mm³&lt;/td&gt;
&lt;td&gt;measured&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A6&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Upper Greensand Formation&lt;/td&gt;
&lt;td&gt;72 km²&lt;/td&gt;
&lt;td&gt;0.7 km&lt;/td&gt;
&lt;td&gt;6 years&lt;/td&gt;
&lt;td&gt;18.8 Mm³&lt;/td&gt;
&lt;td&gt;guessed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A7&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Upper Greensand Formation&lt;/td&gt;
&lt;td&gt;45 km²&lt;/td&gt;
&lt;td&gt;0.0 km&lt;/td&gt;
&lt;td&gt;6 years&lt;/td&gt;
&lt;td&gt;18.8 Mm³&lt;/td&gt;
&lt;td&gt;guessed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Upper Greensand Formation&lt;/td&gt;
&lt;td&gt;39 km²&lt;/td&gt;
&lt;td&gt;0.2 km&lt;/td&gt;
&lt;td&gt;6 years&lt;/td&gt;
&lt;td&gt;18.8 Mm³&lt;/td&gt;
&lt;td&gt;guessed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Upper Greensand Formation&lt;/td&gt;
&lt;td&gt;32 km²&lt;/td&gt;
&lt;td&gt;0.2 km&lt;/td&gt;
&lt;td&gt;6 years&lt;/td&gt;
&lt;td&gt;18.8 Mm³&lt;/td&gt;
&lt;td&gt;guessed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Helsby Sandstone Formation&lt;/td&gt;
&lt;td&gt;25 km²&lt;/td&gt;
&lt;td&gt;4.4 km&lt;/td&gt;
&lt;td&gt;4 years&lt;/td&gt;
&lt;td&gt;15.7 Mm³&lt;/td&gt;
&lt;td&gt;measured&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A13&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Exeter Group&lt;/td&gt;
&lt;td&gt;22 km²&lt;/td&gt;
&lt;td&gt;2.2 km&lt;/td&gt;
&lt;td&gt;5 years&lt;/td&gt;
&lt;td&gt;22.6 Mm³&lt;/td&gt;
&lt;td&gt;inferred&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Helsby Sandstone Formation&lt;/td&gt;
&lt;td&gt;16 km²&lt;/td&gt;
&lt;td&gt;0.5 km&lt;/td&gt;
&lt;td&gt;4 years&lt;/td&gt;
&lt;td&gt;15.7 Mm³&lt;/td&gt;
&lt;td&gt;measured&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A14&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Chalk (Salisbury Plain body)&lt;/td&gt;
&lt;td&gt;7 km²&lt;/td&gt;
&lt;td&gt;1.8 km&lt;/td&gt;
&lt;td&gt;2 days&lt;/td&gt;
&lt;td&gt;0.2 Mm³&lt;/td&gt;
&lt;td&gt;guessed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Helsby Sandstone Formation&lt;/td&gt;
&lt;td&gt;2 km²&lt;/td&gt;
&lt;td&gt;2.6 km&lt;/td&gt;
&lt;td&gt;4 years&lt;/td&gt;
&lt;td&gt;15.7 Mm³&lt;/td&gt;
&lt;td&gt;measured&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Great Oolite Group&lt;/td&gt;
&lt;td&gt;408 km²&lt;/td&gt;
&lt;td&gt;0.0 km&lt;/td&gt;
&lt;td&gt;30 days&lt;/td&gt;
&lt;td&gt;2.5 Mm³&lt;/td&gt;
&lt;td&gt;guessed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A12&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Carboniferous Limestone Supergroup&lt;/td&gt;
&lt;td&gt;21 km²&lt;/td&gt;
&lt;td&gt;0.0 km&lt;/td&gt;
&lt;td&gt;15 days&lt;/td&gt;
&lt;td&gt;1.3 Mm³&lt;/td&gt;
&lt;td&gt;guessed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A11&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Great Oolite Group&lt;/td&gt;
&lt;td&gt;1 km²&lt;/td&gt;
&lt;td&gt;3.4 km&lt;/td&gt;
&lt;td&gt;30 days&lt;/td&gt;
&lt;td&gt;2.5 Mm³&lt;/td&gt;
&lt;td&gt;guessed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Size of body barely matters; kind of rock matters a lot.&lt;/strong&gt; Underground storage is not a tank filled to the edges of the rock. It is a mound of water around a ring of wells, so its volume is set by the ring and by what the rock will give up — not by how much rock there is. The 408 km² Oolite body and the 1 km² one offer the same 2.5 Mm³ to the same well field. But the Greensand offers 18.8 and the limestones 1–2, because they differ in how much water drains out of them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only the sandstone rests on measured figures.&lt;/strong&gt; Every other row is estimated from rock type — a fair guess a geologist could argue with, not a measurement, and the last column says which is which. Earlier versions of this report left those cells blank. That was worse: a blank reads as “nothing is known”, and something is.&lt;/p&gt;
&lt;p&gt;Read that way the table stops being a shortlist and starts being a question. &lt;strong&gt;On these estimates the Greensand and the Exeter Group hold more, and hold it longer, than the sandstone the whole study is built on&lt;/strong&gt; — and the limestones drain in weeks. If those estimates are anywhere near right, the rock this study picked is not obviously the best one. Nobody has measured them, and that is the point.&lt;/p&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/timescale.jpg&quot; alt=&quot;How long a store keeps water, against how much it can hold. Each line is one rock type. Along a line, holding more means draining slower. Between lines, a more transmissive rock gives more volume at the same drainage speed. The shaded band is the speed a store would need if it were to feed a river across a summer.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;How long a store keeps water, against how much it can hold.&lt;/strong&gt; Each line is one rock type. Along a line, holding more means draining slower. Between lines, a more transmissive rock gives more volume &lt;em&gt;at the same drainage speed&lt;/em&gt;. The shaded band is the speed a store would need if it were to feed a river across a summer.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Finding&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Work the leakage and the capacity together and the well-field radius drops out, and so does specific yield. What a store can hold at a chosen drainage speed depends on just two things: &lt;strong&gt;the transmissivity of the rock, and how far you may raise the water table.&lt;/strong&gt; Both enter linearly.&lt;/p&gt;
&lt;p&gt;At a 90-day drainage speed — roughly “empties over a summer” — that gives:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Triassic sandstone (T = 122, published) — &lt;strong&gt;0.9 Mm³&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Great Oolite (T = 1,000, estimated) — &lt;strong&gt;7.4 Mm³&lt;/strong&gt;, eight times as much, needing a 3.4 km field that the 408 km² body has room for.&lt;/li&gt;
&lt;li&gt;Chalk (T = 1,400, published) — &lt;strong&gt;10.4 Mm³&lt;/strong&gt; in principle, but the 7 km² body here is too small and the wrong shape to hold a 1.5 km field.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So a fast-draining store is not necessarily a small one. It is small &lt;em&gt;in this sandstone&lt;/em&gt;. On rock eight times as transmissive the same drainage speed holds eight times the water.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Known unknown&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;What the rock would actually accept is the largest single uncertainty in this study, and it is not resolved here. What the model does instead is avoid depending on it: no number in this report &lt;em&gt;rests&lt;/em&gt; on predicting the rate — where an injection rate is needed a bound is used, and stated.&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;The three tests&lt;/h3&gt;
&lt;p&gt;Every option faces the same three tests.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;What it asks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1. As built&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A scheme switched on in 2010 with empty stores. The record opens on its own driest year, so this is a hard start — and a fair one.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2. Mature&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The same seventeen years with stores already full, as for a scheme running a decade. The gap between 1 and 2 is &lt;em&gt;the cost of being new&lt;/em&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3. Six droughts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The three driest years stitched back to back and run twice. Every day really happened; only the order is invented.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Limitation&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Test 3 is a stress test, &lt;strong&gt;not a forecast&lt;/strong&gt;. Nothing here claims how likely such a sequence is.&lt;/p&gt;
&lt;/div&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/record.jpg&quot; alt=&quot;The record all three tests are run on. Every day of it happened. The top panel shows why the resource is hard to catch: it arrives in brief spikes above the take threshold, not as a steady flow. The bottom panel shows why the year you start in matters — the record opens on its own driest year, which is the hard start Test 1 gives every option, and the three red bars are the years Test 3 stitches together.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;The record all three tests are run on.&lt;/strong&gt; Every day of it happened. The top panel shows why the resource is hard to catch: it arrives in brief spikes above the take threshold, not as a steady flow. The bottom panel shows why the year you start in matters — the record opens on its own driest year, which is the hard start Test 1 gives every option, and the three red bars are the years Test 3 stitches together.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3&gt;The one number to hold on to&lt;/h3&gt;
&lt;p&gt;Every option below is reported the same way, and it is worth fixing what the figure means before meeting it:&lt;/p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;The headline measure&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Million m³ delivered per drought summer&lt;/strong&gt; — water put on fields or into low rivers between April and September of a dry year, averaged over the four driest years in the record.&lt;/p&gt;
&lt;p&gt;Alongside it sits &lt;strong&gt;the percentage of those days on which a survival ration is met&lt;/strong&gt; — enough to keep a crop alive rather than to grow it well. The volume says how much; the percentage says how reliably.&lt;/p&gt;
&lt;p&gt;For scale: the whole area’s licensed agricultural abstraction is about &lt;strong&gt;3 million m³ a year&lt;/strong&gt;. So an option delivering 1 million m³ in a drought summer is meeting roughly a third of a normal year’s licensed demand at the moment it is hardest to supply.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;What is modelled, and what it is built from&lt;/h2&gt;
&lt;p&gt;A reader entitled to be suspicious should be able to see what is measurement, what is modelling, and what is assumption.&lt;/p&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/model-chain.svg&quot; alt=&quot;What is measured, what is modelled, and what is assumed. Solid green outlines are measured; plain outlines are modelled from measurements; dashed amber outlines rest on an assumption.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;What is measured, what is modelled, and what is assumed.&lt;/strong&gt; Solid green outlines are measured; plain outlines are modelled from measurements; dashed amber outlines rest on an assumption.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;How good&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rainfall&lt;/td&gt;
&lt;td&gt;77 EA gauges, 2010–2026&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Measured&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;River flow&lt;/td&gt;
&lt;td&gt;12 EA gauges, daily&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Measured&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terrain&lt;/td&gt;
&lt;td&gt;1 m LiDAR&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Measured&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Geology&lt;/td&gt;
&lt;td&gt;BGS mapping and borehole logs&lt;/td&gt;
&lt;td&gt;Mapped, interpreted for this study&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rock properties&lt;/td&gt;
&lt;td&gt;BGS report WD/97/34&lt;/td&gt;
&lt;td&gt;Published, not site-specific&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Land use&lt;/td&gt;
&lt;td&gt;Crop Map of England 2024&lt;/td&gt;
&lt;td&gt;Satellite classification, confidence 0.49&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abstraction licences&lt;/td&gt;
&lt;td&gt;EA register, one 100 km² window&lt;/td&gt;
&lt;td&gt;Measured, small sample&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moor water levels&lt;/td&gt;
&lt;td&gt;Water Level Management Plans&lt;/td&gt;
&lt;td&gt;Published, 2009–11 vintage&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;What turned out not to need modelling&lt;/h3&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Finding&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Demand is not the constraint.&lt;/strong&gt; Licensed agricultural abstraction is 2.3–3.2 million m³/yr. The water that could physically do good on the arable land alone is about &lt;strong&gt;108 million m³/yr&lt;/strong&gt;. The licence is under 1% of what would be useful — so no option here is limited by whether anyone wants the water. They are all limited by how much can be caught and kept.&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;The honest ledger&lt;/h3&gt;
&lt;h4&gt;Real trade-offs — physical, and they will not go away&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Trade-off&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Big well field vs small&lt;/td&gt;
&lt;td&gt;Large fields hold water longer but cost more and may not fit the rock body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reservoir vs wells&lt;/td&gt;
&lt;td&gt;A reservoir is fast and expensive; the ground is slow and cheap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One large site vs several&lt;/td&gt;
&lt;td&gt;Several catch more water; each needs its own land, consent and plant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Catching floods vs holding levels&lt;/td&gt;
&lt;td&gt;A basin kept empty catches more but is useless as a landscape feature&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Model assumptions — choices behind the numbers&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Assumption&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Effect if wrong&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reservoir realistically buildable&lt;/td&gt;
&lt;td&gt;≤5 Mm³&lt;/td&gt;
&lt;td&gt;Shifts the balance between surface and underground storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rock porosity and transmissivity&lt;/td&gt;
&lt;td&gt;Published regional values&lt;/td&gt;
&lt;td&gt;Scales every underground number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Leaked water returning to rivers&lt;/td&gt;
&lt;td&gt;80%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tested: changes answers by 1–3%.&lt;/strong&gt; Not a risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Settling time before injection&lt;/td&gt;
&lt;td&gt;2 days&lt;/td&gt;
&lt;td&gt;Sets a minimum basin size, ~0.3 Mm³&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flood depth above channel bed&lt;/td&gt;
&lt;td&gt;2 m&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The most influential guess here&lt;/strong&gt; — it decides which sites can fill by gravity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Known unknowns&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;What the rock will accept when injected. No local precedent — and the model holds that rate &lt;strong&gt;fixed across every rock&lt;/strong&gt;, so a more transmissive body gets no credit for accepting water faster, which is the main thing that would shrink the reservoir in front of it.&lt;/li&gt;
&lt;li&gt;Whether injection wells would clog — the usual failure mode of such schemes, and &lt;strong&gt;not modelled at all&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Costs. Nothing here is costed.&lt;/strong&gt; Every comparison is “X delivers more water than Y”, never “X is better value”.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The eight options&lt;/h2&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/scenarios.jpg&quot; alt=&quot;Left: delivery in a drought summer, as built and mature. Middle: the six-year drought — the zigzag is the three-year sequence repeating, not a failure pattern. Right: average annual delivery.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Left:&lt;/strong&gt; delivery in a drought summer, as built and mature. &lt;strong&gt;Middle:&lt;/strong&gt; the six-year drought — the zigzag is the three-year sequence repeating, not a failure pattern. &lt;strong&gt;Right:&lt;/strong&gt; average annual delivery.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;Reservoir&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;As built&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;Mature&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;% of days&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;To rivers&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;Drought yr 1&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;Yrs 2–6&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A&lt;/strong&gt; Reservoir only (3 Mm3)&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;3 Mm³&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;1.16&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;1.16&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;18%&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.00&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.89&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.9–2.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;B&lt;/strong&gt; Aquifer only, direct injection&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.3 Mm³&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;1.22&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;1.26&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;21%&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.38&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;3.51&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.8–2.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C&lt;/strong&gt; Aquifer + reservoir&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;5 Mm³&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;1.90&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;1.96&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;32%&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.49&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;5.75&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.8–2.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;D&lt;/strong&gt; Three sites, three rivers&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;2 × 3 Mm³&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;4.72&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;5.07&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;78%&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;2.51&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;9.68&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;4.8–7.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;E&lt;/strong&gt; Fast rock + slow rock, cascaded&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;2 Mm³&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.89&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.96&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;16%&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.50&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;3.38&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.8–2.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;F&lt;/strong&gt; Gravity-filled basin&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;5 Mm³&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;4.97&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;5.67&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;89%&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.99&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;9.10&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;2.7–7.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;G&lt;/strong&gt; Existing flood storage moor&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;3 Mm³&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;4.29&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;4.67&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;74%&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.81&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;7.53&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;2.7–7.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;H&lt;/strong&gt; The best untested rock&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;5 Mm³&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;2.19&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;2.40&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;39%&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.39&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;7.70&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;0.8–2.3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;How to read the option maps&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Each option below has a small map. Two conventions run through all of them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The basin follows the ground.&lt;/strong&gt; It is drawn as the water surface the terrain would actually hold at that volume, which is why it is never a neat shape. Options F and G are the exception: they are sited rather than screened, and are drawn as a disc of the right area.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The well field is the mound, not a fence line.&lt;/strong&gt; It is drawn at the radius the model gives it, centred on the nearest suitable rock. Where the mound is wider than the outcrop, that is a real consequence of the modelled radius rather than a drawing error.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The model sizes schemes; it does not site them.&lt;/em&gt; So the positions are indicative. The sizes, the radii, which rivers are in play and which rock is being recharged are not.&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;A · Reservoir only&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Specification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reservoir&lt;/td&gt;
&lt;td&gt;3 million m³, about 1 km² at 3 m deep&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aquifer&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intake&lt;/td&gt;
&lt;td&gt;150,000 m³/day, pumped from the Tone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supply&lt;/td&gt;
&lt;td&gt;40,000 m³/day from basin to fields&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipework&lt;/td&gt;
&lt;td&gt;3.5 km river to basin, plus distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;lede&quot;&gt;**1.16 million m³ per drought summer** — enough to cover **18%** of drought-summer days with a survival ration. A basin caught from the river in winter and drawn down through the summer, with no underground storage at all. It gains nothing whatever from being mature, because it has no memory between years.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/option_a.jpg&quot; alt=&quot;Where option A would sit.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Where option A would sit.&lt;/strong&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/tradeoff_a.jpg&quot; alt=&quot;Why 3 million m³, and not more. A bigger basin is not a better one: past about 3 Mm³ the extra surface loses more to evaporation than the extra volume stores. This is the answer to the obvious objection that the reservoir was simply built too small.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Why 3 million m³, and not more.&lt;/strong&gt; A bigger basin is not a better one: past about 3 Mm³ the extra surface loses more to evaporation than the extra volume stores. This is the answer to the obvious objection that the reservoir was simply built too small.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Real trade-off&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Its six-year drought trace is worth a second look: &lt;strong&gt;0.89, 1.33, 2.65, 0.89, 1.33, 2.65&lt;/strong&gt;. Exactly periodic — year four is identical to year one because nothing carried over. If the objective is resilience &lt;em&gt;across&lt;/em&gt; years, surface storage alone cannot provide it at any size this ground allows.&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;B · Aquifer only, no reservoir&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Specification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reservoir&lt;/td&gt;
&lt;td&gt;0.3 million m³ settling pond only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aquifer&lt;/td&gt;
&lt;td&gt;2 km well field in sandstone, ~16 Mm³&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intake&lt;/td&gt;
&lt;td&gt;150,000 m³/day, straight to the wells&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Injection&lt;/td&gt;
&lt;td&gt;150,000 m³/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery&lt;/td&gt;
&lt;td&gt;40,000 m³/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipework&lt;/td&gt;
&lt;td&gt;3.5 km river to basin; 2.7 km basin to well field&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;lede&quot;&gt;**1.26 million m³ per drought summer** — enough to cover **21%** of drought-summer days with a survival ration. River water pumped straight down wells with no basin at all. The cheapest thing to build, but it can only take water while the river is high, and it sends barely-settled flood water into the wells — the arrangement most likely to clog them.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/option_b.jpg&quot; alt=&quot;Where option B would sit. Well field on A3, 2.7 km from the basin.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Where option B would sit.&lt;/strong&gt; Well field on A3, 2.7 km from the basin.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/tradeoff_b.jpg&quot; alt=&quot;Why 150,000 m³/day. With no basin to hold a flood, everything depends on how fast the wells can swallow it — but the curve flattens at 150,000, because beyond that the river, not the wells, is the limit. Spending more on injection buys nothing.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Why 150,000 m³/day.&lt;/strong&gt; With no basin to hold a flood, everything depends on how fast the wells can swallow it — but the curve flattens at 150,000, because beyond that the river, not the wells, is the limit. Spending more on injection buys nothing.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3&gt;C · Aquifer + reservoir&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Specification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reservoir&lt;/td&gt;
&lt;td&gt;5 million m³, ~1.7 km², 2 days settling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aquifer&lt;/td&gt;
&lt;td&gt;2 km well field, ~16 Mm³ capacity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intake&lt;/td&gt;
&lt;td&gt;150,000 m³/day, pumped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Injection&lt;/td&gt;
&lt;td&gt;150,000 m³/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery&lt;/td&gt;
&lt;td&gt;40,000 m³/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipework&lt;/td&gt;
&lt;td&gt;3.5 km river to basin; 2.7 km basin to well field&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;lede&quot;&gt;**1.96 million m³ per drought summer** — enough to cover **32%** of drought-summer days with a survival ration. The conventional managed-recharge scheme: catch the flood in a basin, inject it underground over the following weeks, pump it back in summer. Better than either part alone, and unlike a reservoir it carries water between years. **This is the baseline everything else should be judged against.**&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/option_c.jpg&quot; alt=&quot;Where option C would sit. Well field on A3, 2.7 km from the basin.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Where option C would sit.&lt;/strong&gt; Well field on A3, 2.7 km from the basin.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/tradeoff_c.jpg&quot; alt=&quot;Two dials, and they trade against each other. More basin substitutes for faster wells and vice versa — the contours run diagonally. But the surface flattens past about 5 Mm³ and 150,000 m³/day, which is where the scheme is specified. Spending on either dial beyond that buys very little.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Two dials, and they trade against each other.&lt;/strong&gt; More basin substitutes for faster wells and vice versa — the contours run diagonally. But the surface flattens past about 5 Mm³ and 150,000 m³/day, which is where the scheme is specified. Spending on either dial beyond that buys very little.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3&gt;D · Three sites on three rivers&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Specification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reservoirs&lt;/td&gt;
&lt;td&gt;3 × 2 million m³, one per river&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aquifers&lt;/td&gt;
&lt;td&gt;3 × 1.15 km well field, ~5 Mm³ each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intakes&lt;/td&gt;
&lt;td&gt;3 × 150,000 m³/day — Tone, Isle/Parrett, Brue/Yeo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Injection&lt;/td&gt;
&lt;td&gt;27,000 m³/day per site&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery&lt;/td&gt;
&lt;td&gt;13,000 m³/day per site&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipework&lt;/td&gt;
&lt;td&gt;3 separate systems — 0.1–3.5 km river to basin; 2.7–11.8 km basin to well field&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;lede&quot;&gt;**5.07 million m³ per drought summer** — enough to cover **78%** of drought-summer days with a survival ration. Three separate schemes of the same kind as C, one on each of three river systems, sharing the same total well capacity. Here the landscape does the design rather than a dial. It works for one simple reason — *the rivers do not flood on the same days*, so three modest intakes are busy more often than one large one.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/option_d.jpg&quot; alt=&quot;Where option D would sit. Well field on A3 and A10, 2.7–11.8 km from the basin.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Where option D would sit.&lt;/strong&gt; Well field on A3 and A10, 2.7–11.8 km from the basin.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;What the map adds&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The three sites are not equivalent. All three are modelled on Triassic sandstone, and &lt;strong&gt;the only Triassic sandstone in the study area is in the west&lt;/strong&gt; — so the western site’s wells are 2.7 km from its basin while the two eastern ones are 12 and 20 km away. There is rock beneath the eastern rivers, but it is Greensand and Oolite, and no leakage figure has been derived for either.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;D’s strength does not depend on this.&lt;/strong&gt; It works because three rivers do not flood on the same days, and that stands whatever the rock does. What the map adds is where the cost and the uncertainty sit: either long pipes west, or the first leakage test on an eastern body.&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;E · Fast rock and slow rock, linked&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Specification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reservoir&lt;/td&gt;
&lt;td&gt;2 million m³&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fast store&lt;/td&gt;
&lt;td&gt;Great Oolite, 3.44 km mound, 7.4 Mm³, 90-day half-life&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slow store&lt;/td&gt;
&lt;td&gt;Upper Greensand, 2.0 km mound, 18.8 Mm³, 6.3-year half-life&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rock&lt;/td&gt;
&lt;td&gt;two touching outcrops, both on a river — but both estimated, never measured&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transfer&lt;/td&gt;
&lt;td&gt;30,000 m³/day, fast store to slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intake&lt;/td&gt;
&lt;td&gt;150,000 m³/day&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;lede&quot;&gt;**0.96 million m³ per drought summer** — enough to cover **16%** of drought-summer days with a survival ration. Two genuinely different rocks working together: fractured limestone that drains over a summer to feed the rivers naturally, passing the rest into sand that holds water for years. **Still the worst performer here, and that is the finding.**&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/option_e.jpg&quot; alt=&quot;Where option E would sit. Well field on A10 and A9, 12.5–16.1 km from the basin.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Where option E would sit.&lt;/strong&gt; Well field on A10 and A9, 12.5–16.1 km from the basin.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;On the limestone, a store that drains over a summer holds &lt;strong&gt;7.4 million m³&lt;/strong&gt; — eight times what the sandstone gives at the same speed. The pairing has the storage it always needed. It still comes last.&lt;/p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Why it fails&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Not the rock, and not the plumbing. &lt;strong&gt;Look at when the leak happens.&lt;/strong&gt; A store that half-empties in 90 days is filled by the winter floods and has given most of it back by May. Across the record E returns 0.50 million m³/yr to the rivers. In a &lt;em&gt;drought&lt;/em&gt; summer it returns &lt;strong&gt;0.01&lt;/strong&gt; — because in a dry year the fast store never filled either.&lt;/p&gt;
&lt;p&gt;It feeds the rivers generously in wet years, when they do not need it, and has nothing left in dry ones, when they do. That is this report’s recurring sentence in its sharpest form: &lt;em&gt;a drought is the failure of the winter that would have filled the store.&lt;/em&gt; A passive store cannot escape it, because passive means it drains on the calendar rather than on demand.&lt;/p&gt;
&lt;/div&gt;
&lt;h4&gt;Would a slower store do better?&lt;/h4&gt;
&lt;p&gt;The obvious objection, and worth a sweep rather than an argument — because &lt;strong&gt;a slower store is not a smaller one&lt;/strong&gt;. Volume rises in step with the half-life, so asking for 180 days instead of 90 doubles it rather than trading it away. There is no penalty to pay on that axis.&lt;/p&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/halflife.jpg&quot; alt=&quot;Left: what it delivers to fields, against how big the store has to be. Right: what leaks back to the rivers. The sweep runs from 30 days to three years — a 36-fold range of store size.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Left: what it delivers to fields, against how big the store has to be. Right: what leaks back to the rivers.&lt;/strong&gt; The sweep runs from 30 days to three years — a 36-fold range of store size.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Finding&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Slower is better for the fields, and the gain is almost nothing.&lt;/strong&gt; Across the sweep delivery rises from 0.92 to 1.12 million m³ a drought summer — 21% — while the store it needs grows from 2.5 to &lt;strong&gt;91 million m³&lt;/strong&gt;, a well field 12 km across holding more than most winters produce. &lt;em&gt;Multiply the storage by thirty-six, gain a fifth.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For the rivers there is a real optimum — about 90 days, near enough what the option already uses, feeding 0.21 million m³ over an average summer. In a drought summer it is 0.005 to 0.006 million m³, flat across the whole sweep. No half-life rescues it.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Two further refinements were tried and are kept in the model, off by default: crediting the leak against the day’s river-support release, and holding the fast-to-slow transfer back until the river is too low to abstract from. The first changes almost nothing, because deliberate releases are only 0.02 million m³/yr to begin with. The second moves real water — river baseflow over the record rises from 8.2 to 13.6 million m³, at about 2% of delivery — but not into a drought summer.&lt;/p&gt;
&lt;h3&gt;F · A basin filled by gravity&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Specification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reservoir&lt;/td&gt;
&lt;td&gt;5 million m³ in a natural hollow, ~3 km², under 2 m deep&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filling&lt;/td&gt;
&lt;td&gt;gravity through a sluice — no intake pump&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aquifer&lt;/td&gt;
&lt;td&gt;2 km well field, ~16 Mm³&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Injection&lt;/td&gt;
&lt;td&gt;80,000 m³/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery&lt;/td&gt;
&lt;td&gt;40,000 m³/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipework&lt;/td&gt;
&lt;td&gt;1.5 km river to basin; 2.3 km basin to well field; return channel to a lower point on the same river&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;lede&quot;&gt;**5.67 million m³ per drought summer** — enough to cover **89%** of drought-summer days with a survival ration. The same scheme as C, but the basin sits low enough that the river fills it through a gate when in flood — no intake pump at all. **The best performer of the eight.**&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/option_f.jpg&quot; alt=&quot;Where option F would sit. Sited rather than screened, so the basin is a disc of the right area rather than a real footprint. Well field on A3, 2.3 km from the basin.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Where option F would sit.&lt;/strong&gt; Sited rather than screened, so the basin is a disc of the right area rather than a real footprint. Well field on A3, 2.3 km from the basin.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3&gt;G · An existing flood storage moor&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Specification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reservoir&lt;/td&gt;
&lt;td&gt;3 million m³ held on a moor already used for flood storage — ~10 km² at 0.3 m&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filling&lt;/td&gt;
&lt;td&gt;gravity through the existing inlets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aquifer&lt;/td&gt;
&lt;td&gt;2 km well field, ~16 Mm³&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Injection&lt;/td&gt;
&lt;td&gt;80,000 m³/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery&lt;/td&gt;
&lt;td&gt;40,000 m³/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipework&lt;/td&gt;
&lt;td&gt;inlets and pumping station already exist; new pipe is 1.6 km basin to well field&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;lede&quot;&gt;**4.67 million m³ per drought summer** — enough to cover **74%** of drought-summer days with a survival ration. The same idea as F, on ground that is already flooded every winter on purpose. Curry Moor and its neighbours are filled from the river through existing inlets and emptied by an existing pumping station; this option adds injection plant and keeps some of that water instead of pumping all of it away.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/option_g.jpg&quot; alt=&quot;Where option G would sit. Sited rather than screened, so the basin is a disc of the right area rather than a real footprint. Well field on A3, 1.6 km from the basin.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Where option G would sit.&lt;/strong&gt; Sited rather than screened, so the basin is a disc of the right area rather than a real footprint. Well field on A3, 1.6 km from the basin.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3&gt;H · The best rock nobody has tested&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Specification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reservoir&lt;/td&gt;
&lt;td&gt;5 million m³ — identical to C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aquifer&lt;/td&gt;
&lt;td&gt;Upper Greensand, 2 km well field, 18.8 Mm³, 6.3-year half-life&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intake&lt;/td&gt;
&lt;td&gt;150,000 m³/day — identical to C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Injection&lt;/td&gt;
&lt;td&gt;150,000 m³/day — identical to C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery&lt;/td&gt;
&lt;td&gt;40,000 m³/day — identical to C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipework&lt;/td&gt;
&lt;td&gt;3.5 km river to basin; 12.5 km basin to well field&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confidence&lt;/td&gt;
&lt;td&gt;properties estimated from rock type, never measured&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;lede&quot;&gt;**2.40 million m³ per drought summer** — enough to cover **39%** of drought-summer days with a survival ration. Option C moved onto different ground, and nothing else changed. The Greensand is estimated to hold half again as much water as the sandstone and to keep it half again as long — so this is what better rock is worth, with every other dial held still.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/option_h.jpg&quot; alt=&quot;Where option H would sit. Well field on A9, 12.5 km from the basin.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Where option H would sit.&lt;/strong&gt; Well field on A9, 12.5 km from the basin.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Finding&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better rock is worth about a fifth.&lt;/strong&gt; C delivers 1.96 million m³ a drought summer; H, with 20% more storage held 45% longer, delivers 2.40 — a gain of 23%. Real, and worth having. But the options that reach across the landscape deliver two and a half times C, on the &lt;em&gt;same&lt;/em&gt; rock.&lt;/p&gt;
&lt;p&gt;So the ranking does not turn on finding better ground. It turns on how much water a scheme can catch. That is worth knowing before anyone spends money looking for a better aquifer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Confidence&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Every number in this option, and in E, rests on a transmissivity and a specific yield &lt;strong&gt;inferred from rock type and flagged “guess”&lt;/strong&gt; in the source data. No leakage has ever been measured on the Greensand. Treat H as an &lt;em&gt;upper bound on what better rock could buy&lt;/em&gt;, not as a result: if the estimate is out by a factor of two, so is the answer.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;What the three tests show&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The cost of being new is real but not fatal.&lt;/strong&gt; Maturity is worth between nothing (option A) and about 15% (option F). A scheme commissioned in 2010 would have met little of the 2010–11 drought, simply because it had not yet banked anything.&lt;/p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;The key finding&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The mature store buys about one year.&lt;/strong&gt; Year 1 of the drought test separates the options widely. From year 2 onward each settles into a pattern set by what it can catch from that year’s flows — options A, B, C, E and H all deliver between 0.7 and 2.6 Mm³ regardless of how much storage they hold, and H holds the most of the five.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Nothing collapses.&lt;/strong&gt; Even in six consecutive drought years the driest years still carry enough water at high flow that a scheme keeps delivering something. These schemes do not run dry; they run &lt;em&gt;small&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;All options side by side&lt;/h2&gt;
&lt;p&gt;One chart, one question: on a day in a drought summer, is there enough water to keep a crop alive?&lt;/p&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/days_met.jpg&quot; alt=&quot;Percentage of April–September days in the four driest years on which the scheme delivers at least a survival ration.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;Percentage of April–September days in the four driest years on which the scheme delivers at least a survival ration.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Definition&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;survival ration&lt;/strong&gt; here means 2,700 m³/day — roughly a sixth of what is licensed. It is a stated stand-in, &lt;strong&gt;not an agronomic finding&lt;/strong&gt;: there is no crop model here, and the real figure depends on the crop, the soil and the week. Change the threshold and the percentages move; the &lt;em&gt;ordering&lt;/em&gt; is what matters.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The chart splits into two clear groups. &lt;strong&gt;The five options built on one river cover 16–39% of drought days; the three that reach across the landscape cover 74–89%.&lt;/strong&gt; Every one is sized at its own best configuration, so the gap is not a sizing artefact.&lt;/p&gt;
&lt;p&gt;And the gap survives changing the ground underneath. &lt;strong&gt;H is option C on the best rock in the study area, and it reaches 39% — still less than half of what the weakest landscape-scale option manages on ordinary sandstone.&lt;/strong&gt; The difference is not how much water these schemes store. It is how much they can &lt;em&gt;catch&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;The rhythm of each option&lt;/h3&gt;
&lt;p&gt;A single number per drought summer cannot show &lt;em&gt;when&lt;/em&gt; a scheme hands water over, and that turns out to be most of the difference between them. The next two charts put all eight on the same clock.&lt;/p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;How to read these&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Blue is water going out. The red line is water still in store. Grey behind is rainfall.&lt;/strong&gt; Both charts share one scale and one clock, and every option is running as a mature scheme.&lt;/p&gt;
&lt;p&gt;The pink band at the right is not a forecast. It is the record’s own &lt;strong&gt;first three years replayed as if they were the next three&lt;/strong&gt;, starting the day after the record ends and lined up so the seasons still fall where they should. Each option carries straight on from wherever August 2026 leaves its stores — so the band answers the question a table cannot: &lt;em&gt;if the next three years were like 2010–13, what would this option do?&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/rhythm_abc.jpg&quot; alt=&quot;Options A to D. A’s red line returns to zero every summer and starts each winter from nothing. B, C and D build a store that survives the summer — and note that C’s is still rising in 2024 after fourteen years, which is what “the cost of being new” looks like.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Options A to D.&lt;/strong&gt; A’s red line returns to zero every summer and starts each winter from nothing. B, C and D build a store that survives the summer — and note that C’s is still rising in 2024 after fourteen years, which is what “the cost of being new” looks like.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/rhythm_defg.jpg&quot; alt=&quot;Options E to H, same scale. F and G hold a high store year after year and hand water out on roughly twice as many days as the single-river schemes. E and H sit beside them on the page but behave like the single-river group, which is what they are.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Options E to H, same scale.&lt;/strong&gt; F and G hold a high store year after year and hand water out on roughly twice as many days as the single-river schemes. E and H sit beside them on the page but behave like the single-river group, which is what they are.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Finding&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every option pushes water out at the same rate — the recovery pump is the ceiling and all of them reach it.&lt;/strong&gt; What separates them is how many days a year they can push at all: &lt;strong&gt;128 days for A, 259 for F.&lt;/strong&gt; Not how hard, but how often.&lt;/p&gt;
&lt;p&gt;The red lines say why. A’s returns to zero every summer and starts each winter from nothing — it has no memory, so a bad winter is a bad summer with no appeal. F and G still hold 5.5 and 3.9 million m³ on the 30th of September, which is next year’s opening balance.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;If the next three years were like 2010–13&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Over those three replayed years, &lt;strong&gt;A delivers 8.4 million m³ and F delivers 19.5&lt;/strong&gt; — on 139 and 253 days a year respectively. The three years include the driest in the record, and the options that arrive at 2026 with water already banked are the ones that get through them.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The same thing shows in how steady each option is from year to year. &lt;strong&gt;A’s best year delivers 5 times its worst; F’s ratio is 1.5.&lt;/strong&gt; That is what “smoothing” means in practice — not a gentler daily curve, but a smaller gap between a good year and a bad one.&lt;/p&gt;
&lt;h3&gt;What a scheme looks like from the inside&lt;/h3&gt;
&lt;p&gt;One option in detail, to show the mechanism the table hides. This is C, the conventional basin-plus-wells scheme, over eight years.&lt;/p&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/breathing.jpg&quot; alt=&quot;Rain and river at the top, the two stores in the middle, water out at the bottom. The reservoir (brown) barely registers — it fills and empties within days. The aquifer (red) is the store that matters: it ramps up through each winter and draws down through each summer, and in the wet run of 2020–21 it reaches about 60% of its capacity. The dashed line at the bottom is all the water that could be put to use, not a requirement; the dotted line is the survival ration the report scores against.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Rain and river at the top, the two stores in the middle, water out at the bottom.&lt;/strong&gt; The reservoir (brown) barely registers — it fills and empties within days. The aquifer (red) is the store that matters: it ramps up through each winter and draws down through each summer, and in the wet run of 2020–21 it reaches about 60% of its capacity. The dashed line at the bottom is &lt;em&gt;all&lt;/em&gt; the water that could be put to use, not a requirement; the dotted line is the survival ration the report scores against.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Finding&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The basin is a buffer, not the store.&lt;/strong&gt; Its job is to hold a two-day flood long enough to push it down the wells over the following weeks. Almost none of the water a scheme delivers in August was in the basin in July — it was underground. That is why the reservoir-only option behaves so differently, and why the size of the basin stops mattering above a few million m³.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The same view of the two options that reach across the landscape shows why each of them works, and what each has to respect.&lt;/p&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/breathing_d.jpg&quot; alt=&quot;Option D: three schemes, one colour each — solid for the aquifer, dashed for the basin. The dashed lines are the point. The three basins spike at different times, because the Tone, the Isle and the Brue do not flood on the same days; each one is catching floods the others miss. The three aquifers then ride up together and hold. This is the whole argument for spreading a scheme out, and it is invisible in any single number.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Option D: three schemes, one colour each — solid for the aquifer, dashed for the basin.&lt;/strong&gt; The dashed lines are the point. The three basins spike at &lt;em&gt;different times&lt;/em&gt;, because the Tone, the Isle and the Brue do not flood on the same days; each one is catching floods the others miss. The three aquifers then ride up together and hold. This is the whole argument for spreading a scheme out, and it is invisible in any single number.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Option G has a constraint none of the others do: the moor it would use is not empty ground. It is held to water levels agreed between the Drainage Board, the Environment Agency and Natural England, for farming and for birds.&lt;/p&gt;
&lt;figure class=&quot;figure-wide&quot;&gt;&lt;img src=&quot;/assets/figures/banking-winter-water/breathing_g.jpg&quot; alt=&quot;Option G, drawn in the units its consent is written in. The middle panel is metres of water on the moor, not a percentage, because that is what the Water Level Management Plan regulates. The red line is the moor’s own agreed summer level, 0.30 m above its winter level — the median across 19 structures in the Curry Moor plan of 2011.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;figcaption&gt;&lt;strong&gt;Option G, drawn in the units its consent is written in.&lt;/strong&gt; The middle panel is metres of water on the moor, not a percentage, because that is what the Water Level Management Plan regulates. The red line is the moor’s own agreed summer level, &lt;strong&gt;0.30 m above its winter level&lt;/strong&gt; — the median across 19 structures in the Curry Moor plan of 2011.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;A coincidence worth not over-reading&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The moor never crosses that line. That is &lt;em&gt;by construction&lt;/em&gt;, not by discovery: the option was given 3 million m³ over roughly 10 km², which is 0.3 m, before anyone looked at the plan. What the plan adds is that &lt;strong&gt;0.30 m happens to be exactly the band the moor is already managed through&lt;/strong&gt; — so this option is asking to use depth that is already consented, rather than asking for more.&lt;/p&gt;
&lt;p&gt;That is a reason to look at it and not a reason to assume it is free. The plans set levels &lt;em&gt;by season&lt;/em&gt;, and a recharge scheme wants water held at times the plan may not allow. Whether the timing works is a conversation with the Board and Natural England, not a modelling result.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;What is worth exploring, and why it works&lt;/h2&gt;
&lt;h4&gt;⭐ Let the river fill the basin itself&lt;/h4&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Most promising&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it is.&lt;/strong&gt; A basin sitting low enough that when the river runs high it simply flows in through a gate. No pump. When the flood passes the water drains back to the river, or is pumped underground at leisure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why it works.&lt;/strong&gt; The water arrives in nine bursts a year, two days each. To catch a whole burst by pumping you would need a machine moving 560,000 m³ a day — used nine days a year. A gate costs almost nothing to run and has no such limit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What would stop it.&lt;/strong&gt; The ground has to be in the right place: below the river when it floods, above it when it does not. The screen found candidates, but the estimate of flood level behind them is the weakest number in the study.&lt;/p&gt;
&lt;h4&gt;⭐ Use the moors that already flood&lt;/h4&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Most practical&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it is.&lt;/strong&gt; Several moors are already flooded deliberately in winter to protect towns, with inlets and pumping stations built and operating. Also use that water — put some underground before the moor is drained.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why it works.&lt;/strong&gt; Most of the cost is already spent. The structures exist, the operating practice exists, and the moors already fill and empty on roughly the right rhythm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What would stop it.&lt;/strong&gt; Those moors are managed to agreed levels for farming and for birds, and those agreements would have to be reopened. It needs the Drainage Board and Natural England, not just an engineer.&lt;/p&gt;
&lt;h4&gt;⭐ Spread across several rivers&lt;/h4&gt;
&lt;p class=&quot;entry-meta&quot;&gt;&lt;span&gt;Most robust&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it is.&lt;/strong&gt; Three modest schemes on three different rivers instead of one large one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why it works.&lt;/strong&gt; The rivers do not flood on the same days. Three modest intakes are busy more often than one large one, so they catch about 10% more water for the same total pumping.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What would stop it.&lt;/strong&gt; Three sites means three lots of land, consent, access and maintenance. The water case is good; the cost case is untested.&lt;/p&gt;
&lt;h3&gt;Worth knowing about, but not the answer&lt;/h3&gt;
&lt;h4&gt;A reservoir on its own&lt;/h4&gt;
&lt;h4&gt;Water straight down wells, no basin&lt;/h4&gt;
&lt;h4&gt;A fast-draining store feeding the rivers&lt;/h4&gt;
&lt;h2&gt;What this study does not say&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It does not recommend a scheme.&lt;/strong&gt; Costs would decide between these options and none has been estimated.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It does not claim a return period.&lt;/strong&gt; The six-year drought is a stress test built from real years in an invented order.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It does not predict what the rock will accept.&lt;/strong&gt; No injection has ever been made here.&lt;/li&gt;
&lt;li&gt;Land ownership, designations and consents are unchecked for every candidate site.&lt;/li&gt;
&lt;li&gt;Clogging — the most common way such schemes fail in practice — is not modelled at all.&lt;/li&gt;
&lt;li&gt;The survival threshold is this study’s own, not an agronomist’s.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;What the next steps would be&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Survey river levels at the candidate basins.&lt;/strong&gt; Cheap, quick, and it decides whether the best-performing option is real.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Talk to the Drainage Board&lt;/strong&gt; about the flood-storage moors. If they can double as recharge basins, most of the capital is spent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost the options.&lt;/strong&gt; Wells against earthworks is the trade that decides this.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do one injection test.&lt;/strong&gt; It would remove the largest single uncertainty in the study.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Somerset Levels &amp;amp; Vale of Taunton feasibility study, version 2 · 13 August 2026. Sources: Environment Agency hydrology and abstraction data; British Geological Survey mapping and report WD/97/34; Defra Crop Map of England 2024; Somerset Drainage Boards Consortium Water Level Management Plans; OpenStreetMap contributors. Every figure is reproducible from raw data with a single command.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Where every number comes from&lt;/h2&gt;
&lt;p&gt;Every figure above is produced by a background chapter, and every chapter
regenerates from raw Environment Agency, BGS and Defra data with one
command. They are working documents rather than prose, and they sit
behind this report rather than beside it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/background-chapters/&quot;&gt;The background chapters&lt;/a&gt;&lt;/strong&gt; — all forty-one, grouped by layer: the water, the rock, the demand and the scheme.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/earlier-versions/&quot;&gt;Earlier versions&lt;/a&gt;&lt;/strong&gt; — the drafts this report grew out of, and the corrections between them.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Earlier versions</title>
    <link href="https://themetalevel.org/notes/earlier-versions/"/>
    <updated>2026-08-13T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/earlier-versions/</id>
    <summary>The drafts behind the current report, kept because the corrections between them are part of the record.</summary>
    <content type="html">&lt;p&gt;The current report is &lt;a href=&quot;/notes/banking-winter-water/&quot;&gt;Banking winter water for a dry
summer&lt;/a&gt;, version 2. These are the drafts
behind it, kept because the corrections between them are part of the
record rather than something to tidy away.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/banking-winter-water-v1/&quot;&gt;Banking winter water for a dry summer (version 1)&lt;/a&gt;&lt;/strong&gt; — The first version of the summary report, circulated 12 August 2026. Superseded by version 2, which corrects two figures and adds an eighth option.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/floodmar-somerset-v2/&quot;&gt;FloodMAR Somerset — scheme assessment (v2)&lt;/a&gt;&lt;/strong&gt; — The scheme assessment the report grew out of, with every parameter marked measured, published, derived, placeholder or assumed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/storing-winter-water-underground/&quot;&gt;Storing winter river water underground on the Somerset Levels&lt;/a&gt;&lt;/strong&gt; — The first full paper. Predates the scheme layer entirely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/notes/somerset-working-note-v3/&quot;&gt;Flood-water capture and aquifer storage on the Somerset Levels&lt;/a&gt;&lt;/strong&gt; — The water-accountancy working note: what the model is, what it can say, and what it cannot.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;/notes/banking-winter-water/&quot;&gt;← Back to the report&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Known issues, deferred features and architectural TODOs</title>
    <link href="https://themetalevel.org/notes/lfti-known-issues/"/>
    <updated>2026-08-12T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/lfti-known-issues/</id>
    <summary>A live register: issue, context, priority, and the prompt it belongs in. Items are removed when resolved.</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;A live register: issue, context, priority, and the prompt it belongs in. Items are removed when resolved.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;ARCHITECTURAL / DATA MODEL&lt;/h2&gt;
&lt;h3&gt;A1 — School hierarchy is one level too flat&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; UK Schools currently acts as both a country grouping AND a specific institution. A school admin assigned to “UK Schools” sees all projects under it, which is wrong when multiple UK schools are in the system.
&lt;strong&gt;Should be:&lt;/strong&gt; LFTI root → Country grouping (UK Schools) → Specific school (Bristol Academy) → School admin scoped to their school only.
&lt;strong&gt;Fix:&lt;/strong&gt; Add one hierarchy level. System admin creates specific school nodes. Visibility scoping matches institution_id to specific school node, not country grouping.
&lt;strong&gt;Priority:&lt;/strong&gt; High — must fix before any real schools are onboarded.
&lt;strong&gt;Context:&lt;/strong&gt; Discovered during project setup testing with ukadmin.&lt;/p&gt;
&lt;h3&gt;A2 — parent_id is singular but relations[] expresses multi-parent&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; The node schema has a single &lt;code&gt;parent_id&lt;/code&gt; for tree rendering, with multi-parent expressed via &lt;code&gt;contains&lt;/code&gt; relations. This means a node that genuinely belongs to multiple projects only appears in one place in the tree. The other relationships are only visible in graph mode.
&lt;strong&gt;Current behaviour:&lt;/strong&gt; Correct and intentional for now. Tree view is one lens.
&lt;strong&gt;Risk:&lt;/strong&gt; Interchange nodes (sessions involving two institutions) will need careful handling — their &lt;code&gt;parent_id&lt;/code&gt; should point to whichever institution initiated, with &lt;code&gt;involves&lt;/code&gt; relations to the other. This discipline must be maintained.
&lt;strong&gt;Fix when:&lt;/strong&gt; Interchange nodes are built. Add a note in the interchange prompt to enforce this.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — document the convention clearly, enforce in interchange prompt.&lt;/p&gt;
&lt;h3&gt;A5 — Person nodes not attached to institution/project tree&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; All person nodes (dev seed users, wizard-created staff, class nodes) are currently root-level or loosely attached. They appear in the tree alongside LFTI and UK Schools which is wrong and will become confusing at scale.
&lt;strong&gt;Should be:&lt;/strong&gt; Person nodes sit under their most appropriate parent in the tree — institution node for staff/admins, class node for students, project node for facilitators. &lt;code&gt;parent_id&lt;/code&gt; must be set correctly, not null.
&lt;strong&gt;Fix:&lt;/strong&gt; When creating person nodes via auth seed, project wizard, or manual capture — always set &lt;code&gt;parent_id&lt;/code&gt; to the correct parent. Dev seed users should be reparented: system-level users to &lt;code&gt;inst_lfti&lt;/code&gt;, institution-specific users to their institution node.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — fix in the same prompt as F21 (class roster) since that prompt creates person nodes properly anyway.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during multi-user tree view testing.
&lt;strong&gt;Issue:&lt;/strong&gt; The &lt;code&gt;filterNodesByVisibility()&lt;/code&gt; function uses a simplified institution_id match rather than full graph traversal (walking &lt;code&gt;contains&lt;/code&gt; chains up to find which institution a node belongs to).
&lt;strong&gt;Current behaviour:&lt;/strong&gt; Works correctly for directly tagged nodes. May miss nodes that inherit visibility from a parent without an explicit institution_id in their own meta.
&lt;strong&gt;Fix:&lt;/strong&gt; Implement recursive parent traversal in filterNodesByVisibility(). Check &lt;code&gt;meta.institution_id&lt;/code&gt; on the node first; if absent, walk parent_id chain until an institution node is found.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — needed before multiple real institutions are using the system simultaneously.
&lt;strong&gt;Context:&lt;/strong&gt; Noted in auth prompt as deferred.&lt;/p&gt;
&lt;h3&gt;A4 — Partners visibility rule not fully implemented&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; The &lt;code&gt;_visibility: &amp;quot;partners&amp;quot;&lt;/code&gt; rule is defined (visible to institutions connected via &lt;code&gt;involves&lt;/code&gt; or &lt;code&gt;responds_to&lt;/code&gt; relations) but only a simplified version is implemented. Full graph traversal to determine partnership is deferred.
&lt;strong&gt;Fix:&lt;/strong&gt; When interchange nodes are built, implement the full partners check: a user can see a &lt;code&gt;partners&lt;/code&gt; node if their institution_id has an &lt;code&gt;involves&lt;/code&gt; or &lt;code&gt;responds_to&lt;/code&gt; relation to any ancestor of that node.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — needed for interchange feature.
&lt;strong&gt;Context:&lt;/strong&gt; Noted in auth prompt as deferred.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;FEATURES DEFERRED TO LATER PROMPTS&lt;/h2&gt;
&lt;h3&gt;F1 — Tool selection UI&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Phase nodes currently show a nudge toward the reference tool library but have no guided tool selection flow.
&lt;strong&gt;Should be:&lt;/strong&gt; Filter-based tool cards (individual/group, indoor/outdoor, sync/async etc), select 1–3 tools, progress to next phase. Three selected triggers a move-on prompt but fewer is allowed.
&lt;strong&gt;Priority:&lt;/strong&gt; High — next major feature after project setup.
&lt;strong&gt;Prompt:&lt;/strong&gt; &lt;a href=&quot;http://tool-selection-prompt.md&quot;&gt;tool-selection-prompt.md&lt;/a&gt; (to be written)&lt;/p&gt;
&lt;h3&gt;F2 — Session flow and artefact capture&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; No UI for students to actually run a tool session and upload/create artefacts within a phase.
&lt;strong&gt;Should be:&lt;/strong&gt; Group selects a tool, runs the session, uploads artefacts as block nodes (images, text, drawings). Soft limit of 5 contributions per group per phase as a nudge.
&lt;strong&gt;Priority:&lt;/strong&gt; High — core student-facing feature.
&lt;strong&gt;Prompt:&lt;/strong&gt; &lt;a href=&quot;http://session-flow-prompt.md&quot;&gt;session-flow-prompt.md&lt;/a&gt; (to be written)&lt;/p&gt;
&lt;h3&gt;F3 — Approval flow (async and live session mode)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Approval mode is set during project setup but the actual approval UI is not built yet.
&lt;strong&gt;Should be:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Standard (async): teacher sees a list of pending contributions, approves or flags with a note&lt;/li&gt;
&lt;li&gt;Live session mode: real-time feed of contributions, large approve button, designed for whiteboard display&lt;/li&gt;
&lt;li&gt;Flagged content returns to group with a note
&lt;strong&gt;Priority:&lt;/strong&gt; High — needed before any content is shared externally.
&lt;strong&gt;Prompt:&lt;/strong&gt; &lt;a href=&quot;http://approval-flow-prompt.md&quot;&gt;approval-flow-prompt.md&lt;/a&gt; (to be written)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;F4 — Project dashboard Phase 3&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Project dashboard (overview tab with progress grid, needs-attention items, upcoming sessions) not yet built. Phase 1 and 2 of project setup complete but dashboard is Phase 3.
&lt;strong&gt;Should be:&lt;/strong&gt; Progress grid showing contribution counts per phase, needs-attention notifications, participant summary, upcoming workshop dates.
&lt;strong&gt;Priority:&lt;/strong&gt; High — next step after current phase.
&lt;strong&gt;Prompt:&lt;/strong&gt; &lt;a href=&quot;http://project-setup-prompt.md&quot;&gt;project-setup-prompt.md&lt;/a&gt; Phase 3 (continuation)&lt;/p&gt;
&lt;h3&gt;F5 — Observer project overview page&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Observer role currently sees the same tree view as other users. Should have a dedicated read-only view.
&lt;strong&gt;Should be:&lt;/strong&gt; A clean page showing past and live projects with status indicators and approved Present artefacts only. No access to working nodes. Natural home for light analytics.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — needed before funders/external observers are given accounts.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during multi-user testing.&lt;/p&gt;
&lt;h3&gt;F6 — Collaborative prioritisation tools UI (Stones in Circles etc)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Collate phase tools like Stones in Circles, Matrix Ranking, Pairwise Ranking are defined in the reference instance but have no interactive UI.
&lt;strong&gt;Should be:&lt;/strong&gt; Facilitator-run single-screen tool for stones/voting, matrix, pairwise. Student-facing display. Output saved as a prioritisation artefact node.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — needed for Collate phase sessions.
&lt;strong&gt;Prompt:&lt;/strong&gt; &lt;a href=&quot;http://collate-tools-prompt.md&quot;&gt;collate-tools-prompt.md&lt;/a&gt; (to be written)&lt;/p&gt;
&lt;h3&gt;F7 — Synthesis canvas placeholder&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; The Synthesis node in the Collate phase is explicitly marked as a placeholder. No collaborative drawing/compositing surface exists.
&lt;strong&gt;Should be:&lt;/strong&gt; A shared canvas where groups can produce a collective representation from Gather artefacts. This is the most technically complex piece of Collate.
&lt;strong&gt;Priority:&lt;/strong&gt; Low — deferred intentionally. Placeholder node exists. Do not build until Gather and basic Collate are working well.
&lt;strong&gt;Context:&lt;/strong&gt; Noted in PLA_TOOLS_REFERENCE.md.&lt;/p&gt;
&lt;h3&gt;F8 — Body Map facilitation protocol&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Body Map tool node is marked &lt;code&gt;_status: protocol_pending&lt;/code&gt;. Full facilitation protocol needs to come from Mary Manzole (Kamoto Artistic Director).
&lt;strong&gt;Action required:&lt;/strong&gt; Conversation with Mary Manzole to document the protocol. Update the Body Map node body with the authoritative facilitation notes.
&lt;strong&gt;Priority:&lt;/strong&gt; High — do not run Body Map sessions without this protocol documented.
&lt;strong&gt;Context:&lt;/strong&gt; Noted in PLA_TOOLS_REFERENCE.md.&lt;/p&gt;
&lt;h3&gt;F9 — Transect walk spatial data (GPS variant)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Transect walk currently supports low-tech (hand-drawn path, image upload). GPS-tagged high-tech variant is defined but not built.
&lt;strong&gt;Should be:&lt;/strong&gt; Optional GPS track on a transect walk contribution node. Geotagged observation points. Display on a map view.
&lt;strong&gt;Priority:&lt;/strong&gt; Low — secondary option, hand-drawn is primary.
&lt;strong&gt;Context:&lt;/strong&gt; Identified in Gather/Collate design discussion.&lt;/p&gt;
&lt;h3&gt;F10 — Student voting on tools&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Students can see the tool library but cannot signal which tools they want to use. Should be able to vote/react without unilaterally adding a tool to the project.
&lt;strong&gt;Should be:&lt;/strong&gt; A &lt;code&gt;reacts&lt;/code&gt; relation type. Student node &lt;code&gt;reacts&lt;/code&gt; to a tool node with &lt;code&gt;meta.reaction: &amp;quot;want_to_use&amp;quot;&lt;/code&gt;. Facilitator sees these as requests on the phase node.
&lt;strong&gt;Extension:&lt;/strong&gt; Class-level collation of votes — the votes themselves go through a mini Collate process before the facilitator makes the final selection. Self-referential — the methodology for choosing tools is itself participatory.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during reference instance visibility discussion. Class collation layer added during Phase 3 review.&lt;/p&gt;
&lt;h3&gt;F18 — Group instance nodes&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; No group instance node type exists yet. Group instances should be children of a tool instance node, carrying: member names and roles, modality (digital/paper), status (not started / in progress / submitted / uploaded by proxy).
&lt;strong&gt;Should be:&lt;/strong&gt; The facilitator view of a tool instance shows all group instances and their current state at a glance — who has submitted, who is paper-only, who hasn’t started.
&lt;strong&gt;Priority:&lt;/strong&gt; High — needed before any real sessions run.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during tool instance design discussion.&lt;/p&gt;
&lt;h3&gt;F19 — Coordinate clustering for digital transect walk collation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; When multiple group instances have image map annotations near the same coordinates on a shared reference image, the Collate view should surface this as a cluster with a frequency count — nudging toward the deduplication conversation without forcing it.
&lt;strong&gt;Important constraint:&lt;/strong&gt; This ONLY applies to digital image maps with shared pixel coordinates. Hand-drawn transects and maps cannot be clustered algorithmically — the reconciliation is a human participatory activity (see F23).
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — needed for digital Collate phase of transect walk tool.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during tool instance design discussion.&lt;/p&gt;
&lt;h3&gt;F20 — Contribution body + location as relational finding&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; The image map pin captures the where; the contribution body captures the why-it-matters. The Collate view should display both together for each cluster — not just “12 groups marked this point” but “here is what they said about it.”
&lt;strong&gt;Should be:&lt;/strong&gt; In the Collate surface, each coordinate cluster shows: frequency count, all group names that marked it, and all contribution bodies attached to those annotations, readable side by side.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — the essence capture surface for transect walk collation.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during tool instance design discussion.&lt;/p&gt;
&lt;h3&gt;F21 — Class roster management&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; No formal class roster exists. Students are either person nodes added manually or not in the system at all. Group management cannot work properly without a class list.
&lt;strong&gt;Should be:&lt;/strong&gt; Lightweight person nodes for students — first name + last initial minimum (Tom P), no login required. Teacher enters roster via class node (paste or type list). Roster entries matched to full user accounts if student later gets one. Absent students markable per session, reversible.
&lt;strong&gt;Priority:&lt;/strong&gt; High — needed before group management (F22) works.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during group management design discussion.&lt;/p&gt;
&lt;h3&gt;F22 — Group management view&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; No UI exists for assigning students to groups within a tool instance.
&lt;strong&gt;Should be:&lt;/strong&gt; Pre-Start view within a tool instance showing class list on one side, groups on the other. Every student starts unassigned. Teacher (or students) assigns to groups. View shows: unassigned students highlighted, groups with missing roles flagged, absent markers. Must be completable in under 5 minutes for a class of 30. States: unassigned / in group no role / in group with role / absent / arrived late (addable mid-session).
&lt;strong&gt;Priority:&lt;/strong&gt; High — needed before real sessions run.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during group management design discussion.&lt;/p&gt;
&lt;h3&gt;F23 — Map Reconciliation as a Collate tool&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Hand-drawn maps from Gather cannot be algorithmically clustered. The reconciliation of multiple hand-drawn maps into one agreed reference map is itself a meaningful participatory activity.
&lt;strong&gt;Should be:&lt;/strong&gt; A specific Collate tool instance type — “Map Reconciliation” — where input is a collection of hand-drawn map/transect images from Gather and output is a collaboratively produced single reference image. Groups compare drawings, negotiate what counts as the same place, produce an agreed version.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — add to reference instance tool library when Collate tools are built.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during transect walk collation discussion.&lt;/p&gt;
&lt;h3&gt;F24 — Student group assignment and contribution permissions&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Current state:&lt;/strong&gt; Students are read-only — no “+ Add contribution” buttons visible at any level. Facilitator/admin can add contributions at tool instance level (class example) and to any group instance. This is an acceptable interim state for facilitator-led sessions.
&lt;strong&gt;Problem:&lt;/strong&gt; Without knowing which group a student belongs to, the system cannot grant contribution rights to their group only. Granting rights to all groups is too permissive.
&lt;strong&gt;Three options:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option A — Proper student accounts linked to group membership (long term)&lt;/strong&gt;
Students have login credentials. User record links to person_node. Person_node is a member of a specific group_instance. System knows who they are and what group they belong to. Requires F21 (class roster), F22 (group allocation), and F12 (invite/account creation). Also requires a safeguarding/data protection framework for creating accounts for minors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option B — Adhoc group token login (recommended interim)&lt;/strong&gt;
No individual student accounts needed. Each group_instance gets a short token/PIN (e.g. “GROUP1-X7K2”) printed on the group’s worksheet (F15). Any device entering that token gets group-scoped permissions for this tool instance — can add contributions to that group only, see that group’s work, nothing else. Token expires when tool instance is completed or manually invalidated. No email, no password, no personal data stored. Maps naturally onto the printable worksheet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option C — Hybrid (long term)&lt;/strong&gt;
Students with accounts get full individual identity and proper group assignment. Students without accounts use a group token as lightweight fallback. Both work simultaneously.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recommended path:&lt;/strong&gt; Build Option B alongside F15 (printable sheet) — the group token prints on the worksheet naturally. Option A/C follows when a data protection framework for student accounts is in place.
&lt;strong&gt;Priority:&lt;/strong&gt; High — needed before real student-facing sessions run.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during contribution permission review.
&lt;strong&gt;Issue:&lt;/strong&gt; Current implementation adds tool references to a phase node but does not create a tool instance node as a child. The instance is where the live facilitation plan, session steps, timing, materials, and contributions should live. The reference tool node is the canonical definition; the instance is the running version for a specific class on a specific day.
&lt;strong&gt;Should be:&lt;/strong&gt; Selecting a tool creates an instance node (type: &lt;code&gt;tool_instance&lt;/code&gt;) as a child of the phase node, with a &lt;code&gt;references&lt;/code&gt; relation to the source reference tool node. The instance node inherits the facilitation steps from the reference as a starting point, which the facilitator can edit. Contributions attach to the instance, not the phase node directly.
&lt;strong&gt;Priority:&lt;/strong&gt; High — needed before real sessions run. Current contribution attachment to phase node is a temporary structure.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during Phase 3 tool browser review.&lt;/p&gt;
&lt;h3&gt;F14 — Tool flow suggestions (greying/highlighting based on prior selections)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; No recommendation layer exists to guide facilitators toward tools that complement what has already been selected in earlier phases or movements.
&lt;strong&gt;Should be:&lt;/strong&gt; When browsing tools for a phase, tools that flow well from previously selected tools are subtly highlighted. Tools that would be redundant or clash are subtly greyed. Based on &lt;code&gt;feeds&lt;/code&gt; and &lt;code&gt;sequence&lt;/code&gt; relations between reference tool nodes — data already exists in the graph, just not surfaced.
&lt;strong&gt;Example:&lt;/strong&gt; Body Map selected in Past→Gather → Story Circle and River of Life gently highlighted for Situation→Gather. Venn Diagram actual/ideal highlighted for any →Collate phase following a narrative Gather tool.
&lt;strong&gt;UI pattern:&lt;/strong&gt; Subtle — a small compatibility indicator on each card, not a hard block. Facilitator’s judgment always overrides.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — valuable but not blocking. Build after tool instances (F13) are working.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during Phase 3 tool browser review.&lt;/p&gt;
&lt;h3&gt;F11 — Academic calendar display&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Session dates are stored as ISO UTC. Display should be localised to each institution’s academic calendar (UK terms, NZ terms, Zambian school year).
&lt;strong&gt;Current behaviour:&lt;/strong&gt; Dates display as ISO or generic format.
&lt;strong&gt;Fix:&lt;/strong&gt; Add calendar localisation layer. Institution node carries &lt;code&gt;meta.academic_calendar&lt;/code&gt;. Display layer translates ISO dates into the right term/week framing for each user’s institution.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — needed when multiple countries are running simultaneously.&lt;/p&gt;
&lt;h3&gt;F12 — Invite system for staff and students&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Staff and student emails are stored in person node meta during project setup but no actual invite is sent.
&lt;strong&gt;Should be:&lt;/strong&gt; Email invite with a link that creates their account and associates them with the correct institution and project automatically.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — currently requires manual account creation by system admin.
&lt;strong&gt;Context:&lt;/strong&gt; Noted in project setup prompt as placeholder.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;UI / UX BUGS&lt;/h2&gt;
&lt;h3&gt;U1 — Wizard tab state loss on step switch&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; If a user enters details on the Schedule step (e.g. specific dates) then switches to another step and back, their edits are lost.
&lt;strong&gt;Fix:&lt;/strong&gt; Store wizard form state in a persistent local object rather than reading directly from DOM inputs on step change. Read from the object, write to it on every input event.
&lt;strong&gt;Priority:&lt;/strong&gt; Low — minor UX issue, doesn’t affect functionality.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during project setup testing.&lt;/p&gt;
&lt;h3&gt;U2 — Student delete permissions too broad&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Delete button is hidden for student role globally, but students should be able to delete nodes they themselves created (e.g. their own contribution block nodes).
&lt;strong&gt;Fix:&lt;/strong&gt; Check both role AND whether &lt;code&gt;node.meta.created_by === state.currentUser.id&lt;/code&gt; before showing/hiding delete. Students can delete their own; cannot delete others’.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — before student-facing sessions go live.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during multi-user testing.&lt;/p&gt;
&lt;h3&gt;U4 — Reference tool filter editor missing existing value picker&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; The filter tag editor on reference tool nodes shows current values as removable pills and a free-text “add value” input, but there is no way to see and select from existing values already used by other tools for that filter type. A facilitator adding “playing fields” to location has no way to know if another tool already uses “playing_fields” (underscore) vs “playing fields” (space) — leading to inconsistent values and broken filtering.
&lt;strong&gt;Should be:&lt;/strong&gt; The “add value” input should show a dropdown of existing values for that filter type (derived from all tool nodes’ meta, as per the filter pill source-of-truth fix) as the user types — a typeahead/autocomplete. Selecting an existing value ensures consistency. Free text entry still allowed for genuinely new values.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — important for filter consistency before many tools are edited.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during filter editor review after Piece 1.&lt;/p&gt;
&lt;h3&gt;U5 — Reference tool filter tags layout is purely vertical, too long&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Filter tag groups (format, location, modality, duration, tech_level) stack vertically, causing the tool node content section to scroll excessively. Each filter type takes a full row even when its values would fit inline.
&lt;strong&gt;Should be:&lt;/strong&gt; Filter tags laid out horizontally — filter type label followed by its value pills on the same row, wrapping only when necessary. Multiple filter rows should fit in one or two visual rows total rather than five separate vertical blocks. Compact, scannable, not overwhelming.
&lt;strong&gt;Priority:&lt;/strong&gt; Low — cosmetic but affects usability of the tool editor for anyone editing multiple tools.
&lt;strong&gt;Context:&lt;/strong&gt; Identified during filter editor review after Piece 1.
&lt;strong&gt;Issue:&lt;/strong&gt; As the node tree grows with multiple projects and reference tools, the left panel tree may become unwieldy. No virtual scrolling or lazy loading implemented.
&lt;strong&gt;Fix:&lt;/strong&gt; Consider collapsing all but the active project by default. Lazy-load children on expand rather than rendering the full tree on load.
&lt;strong&gt;Priority:&lt;/strong&gt; Low — not a problem yet, will become one at scale.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;SECURITY / ACCESS CONTROL&lt;/h2&gt;
&lt;h3&gt;S1 — No enforcement of reference node read-only status&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Reference nodes (&lt;code&gt;_level: reference&lt;/code&gt;) are currently editable by all authenticated users. This is intentional during development but should be locked down before real schools are onboarded.
&lt;strong&gt;Fix:&lt;/strong&gt; In save/delete handlers, check &lt;code&gt;meta._level === &#39;reference&#39;&lt;/code&gt; and require &lt;code&gt;superadmin&lt;/code&gt; role to edit. Show read-only styling for all other roles (already partially implemented visually).
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — before onboarding real institutional users.
&lt;strong&gt;Context:&lt;/strong&gt; Intentionally left editable for development convenience.&lt;/p&gt;
&lt;h3&gt;S2 — No HTTPS&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Running on HTTP locally. Cookies marked &lt;code&gt;secure: false&lt;/code&gt; for development. Must enable HTTPS before any deployment beyond local dev.
&lt;strong&gt;Fix:&lt;/strong&gt; Add SSL certificate (Let’s Encrypt for self-hosted, automatic on most cloud platforms). Uncomment &lt;code&gt;secure: true&lt;/code&gt; on cookie settings in api/auth.js.
&lt;strong&gt;Priority:&lt;/strong&gt; High — before any external deployment.
&lt;strong&gt;Context:&lt;/strong&gt; Noted in auth prompt with a comment in the code.&lt;/p&gt;
&lt;h3&gt;S3 — No rate limiting on auth endpoints&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Login endpoint has no rate limiting. Vulnerable to brute force attacks.
&lt;strong&gt;Fix:&lt;/strong&gt; Add &lt;code&gt;express-rate-limit&lt;/code&gt; to the login route. 10 attempts per 15 minutes per IP.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — before external deployment.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;CONTENT / METHODOLOGY&lt;/h2&gt;
&lt;h3&gt;C1 — Several PLA tool nodes have thin content&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Some tool nodes in the reference instance have brief descriptions rather than full facilitation notes. River of Life, Timeline, Peer Interview, Hot Seating, and Story of Self in particular need richer body content.
&lt;strong&gt;Fix:&lt;/strong&gt; Expand body text for these nodes. Draw from the source documents in the project (EQUINET toolkit, AFCAP slides, Episcopal Relief transect walk guide).
&lt;strong&gt;Priority:&lt;/strong&gt; Medium — before facilitators are using the reference instance as a planning resource.&lt;/p&gt;
&lt;h3&gt;C2 — No facilitation notes for Present phase tools&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Present phase tool nodes (Short Video, Podcast, Zine, Social Channel) have descriptions but no facilitation guidance.
&lt;strong&gt;Fix:&lt;/strong&gt; Add practical facilitation notes — equipment needed, how to brief students, common pitfalls, time estimates.
&lt;strong&gt;Priority:&lt;/strong&gt; Medium.&lt;/p&gt;
&lt;h3&gt;C3 — Cross-cohort tool variants not fully documented&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Issue:&lt;/strong&gt; Several tools have cross-cohort variants described in PLA_TOOLS_REFERENCE.md (transect walk as cross-cohort presentation, body map comparison, river of life side-by-side) but these variants are not yet represented as separate nodes or documented as facilitation options within the tool nodes.
&lt;strong&gt;Fix:&lt;/strong&gt; Add variant block nodes under relevant tools, or expand tool node bodies with cross-cohort variant sections.
&lt;strong&gt;Priority:&lt;/strong&gt; Low — needed when interchange feature is built.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Participatory tools — reference instance content</title>
    <link href="https://themetalevel.org/notes/lfti-tools-reference/"/>
    <updated>2026-08-12T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/lfti-tools-reference/</id>
    <summary>The source of truth for seeding the reference instance node tree. Each tool becomes a node; each section heading a phase or category.</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;The source of truth for seeding the reference instance node tree. Each tool becomes a node; each section heading a phase or category. Provenance is preserved throughout, because methodology origins matter.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;PRINCIPLES &amp;amp; ETHOS&lt;/h2&gt;
&lt;h3&gt;(Meta-level — governs how all tools are used)&lt;/h3&gt;
&lt;p&gt;These are not tools. They are the conditions under which tools work.
A tool used without these principles produces data. A tool used with them produces understanding.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Handing Over the Stick&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Robert Chambers, PRA tradition
&lt;strong&gt;What it means:&lt;/strong&gt; The facilitator’s job is to give up control of the process as quickly as possible. The moment the facilitator holds the pen, marker, or stone, they own the output. The goal is to place those instruments in the hands of participants as soon as the activity is understood. In a school context: the facilitator is not the teacher. The student holds the pen.
&lt;strong&gt;Watch for:&lt;/strong&gt; Facilitators who “help” by writing, drawing, or arranging on behalf of participants. This is the most common way the methodology is undermined.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Triangulation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA/PLA tradition, Robert Chambers
&lt;strong&gt;What it means:&lt;/strong&gt; No single tool, source, or analyst tells the whole story. Use multiple methods (methods triangulation), ask the same question of different people (source triangulation), and have different people analyse the same data (analyst triangulation). When findings converge across methods and sources, you can have more confidence. When they diverge, that divergence is itself important information.
&lt;strong&gt;In LFTI:&lt;/strong&gt; The pre-perceptions instrument, the body map, and the transect walk should produce overlapping and sometimes contradictory stories about the same students’ experience. The contradictions are data.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Sitting Down&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA field practice
&lt;strong&gt;What it means:&lt;/strong&gt; Literally and metaphorically. The outside facilitator positions themselves physically below or level with community members — sitting on the ground, not standing at a flipchart. In a school context this is radical: adults stand, students sit. Reversing this changes the power in the room immediately. Even moving from behind a desk to sitting in a circle changes what is possible.
&lt;strong&gt;Watch for:&lt;/strong&gt; The facilitator who stands while students sit. The adult who controls the front of the room. The arrangement of furniture that recreates the classroom hierarchy inside what is supposed to be a different kind of space.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Optimal Ignorance&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Robert Chambers, PRA tradition
&lt;strong&gt;What it means:&lt;/strong&gt; You do not need to know everything. You need to know enough to act usefully. Trying to be comprehensive produces paralysis and positions the facilitator as the one who must understand before the community can proceed. Accept that you will not understand everything, that some things will remain opaque, and that this is fine.
&lt;strong&gt;In LFTI:&lt;/strong&gt; A facilitator going into a Zambian classroom does not need to fully understand the Zambian education system before beginning. What they need is enough humility to listen well.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Offsetting Biases&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA/PLA tradition
&lt;strong&gt;What it means:&lt;/strong&gt; In any group, some voices are structurally more likely to be heard: older, male, confident, fluent in the dominant language, higher status. Participatory methodology requires actively seeking the voices that the room is not designed for. This means disaggregating groups by gender, age, confidence level. It means asking who is not speaking and why. It means creating conditions — anonymity, drawing, movement — where those without verbal confidence can still contribute.
&lt;strong&gt;In LFTI:&lt;/strong&gt; Who speaks in a UK classroom? Who speaks in a Zambian classroom? Who never speaks? The methodology must be designed to reach the student who has learned that their voice is not wanted.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Facilitation Not Extraction&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PLA/community development tradition
&lt;strong&gt;What it means:&lt;/strong&gt; You are not mining data from people. You are enabling people to reflect on and articulate what they already know. The process has value independent of any output it produces. A student who has mapped their school, told a story about their body, and ranked what matters to them has done something for themselves — not just for a researcher.
&lt;strong&gt;Watch for:&lt;/strong&gt; Treating students as data sources rather than as the primary beneficiaries of the process. Rushing to outputs without allowing reflection time. Taking the artefacts away without leaving copies with the participants.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;The Body as Instrument&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Theatre for Development / Augusto Boal / Kamoto Community Arts
&lt;strong&gt;What it means:&lt;/strong&gt; Knowledge that cannot be spoken can be performed. Movement, gesture, posture, and voice carry meaning that survives translation across language, age, and culture. When a student cannot find words for their experience of school, they may be able to show it with their body — in a frozen image, a walk, a sound, a gesture. This is not a lesser form of knowledge. It is often a more honest one.
&lt;strong&gt;In LFTI:&lt;/strong&gt; The body is the first instrument available to every student in every context, regardless of literacy, language, or resources. Kamoto’s methodology is built on this. It is why performance, image theatre, and the body map are core tools, not optional extras.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;The Rehearsal for Reality&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Augusto Boal, Theatre of the Oppressed
&lt;strong&gt;What it means:&lt;/strong&gt; Theatre and performance provide a protected space to try out what cannot be tried in ordinary life. A student can play the headteacher. A Zambian student can play a Bristol student. The role distance is both protective (you are not speaking as yourself, so you are safer) and generative (you discover things in role that you did not know you knew). The rehearsal is not a simulation — it is a form of genuine exploration.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Insider Knowledge is Primary&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Action Research / Participatory Action Research tradition
&lt;strong&gt;What it means:&lt;/strong&gt; The researcher is not more expert than the researched. The student is the expert on their own experience of school. The facilitator’s job is to create conditions in which that expertise can be expressed, examined, and acted upon — not to interpret it, correct it, or replace it with academic knowledge. The student’s account of what school is like is primary data. It is not anecdote.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Reflection-Action Spiral&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Action Research / Kurt Lewin / Paolo Freire
&lt;strong&gt;What it means:&lt;/strong&gt; You do not plan completely, then act, then evaluate. You act, reflect on what happened, replan, act again. Each cycle of Gather→Collate→Present is one turn of this spiral. The output of Present is not the end — it is the input to the next Gather. Understanding deepens through iteration, not through increasingly comprehensive planning.
&lt;strong&gt;In LFTI:&lt;/strong&gt; The three movements (Past, Situation, Futures) are three turns of the spiral. The Whole cycle is a fourth turn that reflects on all three.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Ethical Practice&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Research ethics / child safeguarding / participatory traditions
&lt;strong&gt;What it means:&lt;/strong&gt; Several non-negotiable principles govern all LFTI activities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Informed consent&lt;/strong&gt; — participants (and for minors, guardians) understand what they are doing, what will happen to their contributions, and can withdraw at any time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do no harm&lt;/strong&gt; — no activity should leave a participant in a more vulnerable position than before. This includes emotional harm from activities that surface difficult memories without adequate support.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anonymisation&lt;/strong&gt; — student stories and artefacts are anonymised by default unless a student explicitly chooses to be named.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Image rights&lt;/strong&gt; — photographs, videos, and body maps involving students require specific consent. Copies belong first to the participant.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The camera warning&lt;/strong&gt; — cameras and recording devices change the dynamic of a room. Use with caution, use with consent, use sparingly.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;GATHER PHASE TOOLS&lt;/h2&gt;
&lt;h3&gt;Pre-perceptions Instrument&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Green Living Movement (Emmanuel Mutambashiku), Zambia
&lt;strong&gt;Phase:&lt;/strong&gt; Gather (runs twice — once at start of whole project, once after exchange)
&lt;strong&gt;Format:&lt;/strong&gt; Individual, silent. A4 paper folded into four quadrants.
&lt;strong&gt;Time:&lt;/strong&gt; 15–20 minutes each instance&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The four quadrants:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What I think of myself (as a learner, a young person, someone from this place)&lt;/li&gt;
&lt;li&gt;What I think of them (students in the other countries, before knowing them)&lt;/li&gt;
&lt;li&gt;What I think they think of me&lt;/li&gt;
&lt;li&gt;What I think they think of themselves&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Process:&lt;/strong&gt; Completed individually and in silence before any introduction or context-setting. No discussion during. Facilitator collects — or students keep and bring back. Run again at the end of the full exchange. The delta between first and second instance is the primary evaluation measure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Critical rule:&lt;/strong&gt; Do not explain, correct, or discuss responses during the first instance. The pre-perception must be genuinely pre. Any framing before the instrument contaminates it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Feeds into:&lt;/strong&gt; Whole cycle → Gather (second instance), Present (delta reveal as evaluation artefact)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This tool runs across the whole project, not just one movement. It is a Gather tool in structure but an evaluation instrument in function.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Observation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA/PLA tradition (AFCAP, Chambers)
&lt;strong&gt;Phase:&lt;/strong&gt; Gather
&lt;strong&gt;Format:&lt;/strong&gt; Individual or paired, with notepad. Can be structured (specific things to look for) or unstructured (open observation).
&lt;strong&gt;Time:&lt;/strong&gt; Flexible — from 10 minutes to a full session&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it captures:&lt;/strong&gt; People, resources, spatial dynamics, power indicators, movement patterns, what is visible vs hidden, what is named vs unnamed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In a school context:&lt;/strong&gt; Who moves freely through the school? Who is confined? Where do students go when they have choice? Where are the unofficial gathering places? What does the staffroom door communicate? What is on the walls, and who put it there?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Facilitation note:&lt;/strong&gt; The facilitator observes alongside participants, not instead of them. Participants are observing their own environment — they are the experts. The facilitator’s role is to provide a prompt and hold the time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Low-tech:&lt;/strong&gt; Notepad and pencil.
&lt;strong&gt;High-tech:&lt;/strong&gt; Phone camera, voice memo, annotated photograph.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Semi-structured Checklist Interview&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA/PLA tradition (AFCAP)
&lt;strong&gt;Phase:&lt;/strong&gt; Gather
&lt;strong&gt;Format:&lt;/strong&gt; Individual (key informant) or group (focus group). Two facilitators recommended — one to facilitate, one to note.
&lt;strong&gt;Time:&lt;/strong&gt; Individuals: 45–60 minutes. Groups: 90–120 minutes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A checklist of topics, not a questionnaire. The order is flexible.&lt;/li&gt;
&lt;li&gt;Open-ended questions only: What? Why? When? Who? How? Where?&lt;/li&gt;
&lt;li&gt;The interviewer follows the interviewee’s direction — unexpected topics are welcomed.&lt;/li&gt;
&lt;li&gt;Key informant variant: for those with specific expertise (a teacher, a caretaker, a school governor).&lt;/li&gt;
&lt;li&gt;Focus group variant: for groups with shared experience (a year group, a friendship group, students who travel far to school).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;In LFTI:&lt;/strong&gt; Semi-structured interviews with teachers are a specific variant — the teacher as key informant on the system they operate within, not as an authority figure. The semi-structured format protects against the interview becoming a defence of current practice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Facilitator note:&lt;/strong&gt; The interviewer’s job is to be genuinely curious. If you already know what you think the answers are, you will not hear what is actually being said.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Transect Walk&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA/PLA tradition (AFCAP, Episcopal Relief &amp;amp; Development, Chambers)
&lt;strong&gt;Phase:&lt;/strong&gt; Gather
&lt;strong&gt;Format:&lt;/strong&gt; Small groups (pairs or up to 8). Multiple routes can run simultaneously.
&lt;strong&gt;Time:&lt;/strong&gt; 1–3 hours including debrief&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; A structured observational walk between two points, crossing as many different zones of the school/community as possible. The walk produces a diagram — hand-drawn, with annotations — that becomes the primary artefact.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Facilitation steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Route planning&lt;/strong&gt; — choose a transect that crosses maximum diversity of zones (classroom, corridor, playground, entrance, boundary, off-site)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Introduction&lt;/strong&gt; — share the purpose and focus (e.g. “we’re looking at where students have and don’t have voice”)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Walk&lt;/strong&gt; — stop at zone transitions. Ask: What do you see? Who do you see and what are they doing? What happens here that doesn’t happen elsewhere? What is missing here?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Talk to people along the way&lt;/strong&gt; — brief, informal, genuine curiosity. Not an interview — a conversation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Draw as you go&lt;/strong&gt; — one person in each group sketches the route and marks features. The sketch is intentionally rough. Relative scale (what is drawn larger) is information.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zone debrief&lt;/strong&gt; — after the walk, compile the diagram. Identify distinct zones. What characterises each? What assets, problems, opportunities are in each zone?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Low-tech:&lt;/strong&gt; Paper, pencil, chalk on ground for the debrief diagram.
&lt;strong&gt;High-tech variant (secondary):&lt;/strong&gt; GPS track, geotagged photos, digital annotation on a base map. This is a secondary option — the hand-drawn version is primary because the distortions in hand-drawn maps are data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The distortion principle:&lt;/strong&gt; A student who draws the playground three times bigger than the classroom is telling you something about where they feel alive. Do not correct the scale. Preserve it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pairs to gallery:&lt;/strong&gt; Ten pairs produce ten transect diagrams. In Collate, these ten diagrams are displayed together. What is consistent across all ten? What is idiosyncratic? The collection is the data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;As presentation:&lt;/strong&gt; The transect walk can itself be the presentation — participants lead others (community members, other cohorts, decision-makers) along the route, narrating what they found. The walk is the report.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Body Map&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Kamoto Community Arts / Mary Manzole (Artistic Director, Kamoto)
&lt;strong&gt;Phase:&lt;/strong&gt; Gather (primary — Past movement). Can extend to Situation and Futures.
&lt;strong&gt;Format:&lt;/strong&gt; Pairs, then individual, then gallery sharing.
&lt;strong&gt;Time:&lt;/strong&gt; 2–3 hours including gallery and discussion
&lt;strong&gt;Materials:&lt;/strong&gt; Large paper (A1 or larger — wallpaper, flipchart sheets joined), chalk (if on floor/ground), markers, pens, paint if available.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; One person lies on the paper while their partner traces the outline of their body. The outline becomes a map. The maker then fills their body map with stories, memories, feelings, and images placed on the part of the body where they feel that thing lives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of what might be placed:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A broken arm from childhood riding a horse — placed on the arm&lt;/li&gt;
&lt;li&gt;Grief for a grandmother — placed in the hair, or the chest, or wherever it lives for this person&lt;/li&gt;
&lt;li&gt;Anxiety about exams — placed in the stomach&lt;/li&gt;
&lt;li&gt;Pride in running — placed in the legs&lt;/li&gt;
&lt;li&gt;A song learned from a parent — placed in the throat or the ears&lt;/li&gt;
&lt;li&gt;A journey — placed in the feet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The spatial placement is the analysis.&lt;/strong&gt; You do not describe where something lives — you show it. Where people place things is not arbitrary. The body knows things that language doesn’t always reach.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Facilitation steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The tracing&lt;/strong&gt; — in silence. The person being traced lies still. The tracer is careful and attentive. This act itself is significant — being carefully attended to is not a common experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Individual mapping&lt;/strong&gt; — each person fills their own outline alone, working from inside the boundary someone else drew for them. No instruction about what to include — only the prompt: “place what you want to share, where it lives in your body.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gallery&lt;/strong&gt; — maps are displayed. The group walks the gallery in silence first. No explanations yet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sharing&lt;/strong&gt; — makers can choose to share what they’ve placed, or not. Nothing is compulsory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SHOWED analysis&lt;/strong&gt; — group discussion: What do you &lt;em&gt;see&lt;/em&gt;? What is &lt;em&gt;happening&lt;/em&gt; in these bodies? How does this relate to &lt;em&gt;our&lt;/em&gt; lives? &lt;em&gt;Why&lt;/em&gt; are these stories here? What can we &lt;em&gt;do&lt;/em&gt;?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Cross-cohort power:&lt;/strong&gt; A UK student’s body map alongside a Zambia student’s body map, displayed without captions. The viewer can see before reading: what stories do these two bodies share? Where do they diverge? The chest full in one and empty in another. The feet loaded in one, light in another.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT — Facilitation note:&lt;/strong&gt; This tool surfaces personal and sometimes painful material. It must be facilitated by someone who knows how to hold that space — not just manage an activity. Mary Manzole’s facilitation protocol is the authoritative version for LFTI. &lt;strong&gt;This node is a placeholder until that protocol is documented in conversation with Mary.&lt;/strong&gt; Do not use this tool without adequate facilitation preparation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ethical note:&lt;/strong&gt; Body maps are personal and may be intimate. Explicit consent is required before displaying or photographing them. The map belongs to its maker. Copies stay with participants.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Photo Walk / Participatory Photography&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PhotoVoice methodology (Wang &amp;amp; Burris, 1997) / Participatory Photography tradition
&lt;strong&gt;Phase:&lt;/strong&gt; Gather
&lt;strong&gt;Format:&lt;/strong&gt; Individual or paired. Camera/phone distributed or participants use own devices.
&lt;strong&gt;Time:&lt;/strong&gt; 45–90 minutes walk + 30–60 minutes SHOWED analysis&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Participants are given a prompt and asked to photograph their school/community in response. The prompt should be open: “photograph what matters to you about this place” or “photograph what school feels like” or “photograph what you wish others could see.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The photograph as framing device:&lt;/strong&gt; Giving someone a camera is giving them the power to say “this is what I want to look at.” What students choose to photograph — and what they choose not to — is the data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SHOWED analysis:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;S&lt;/strong&gt; — What do you &lt;em&gt;See&lt;/em&gt; in this photograph?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;H&lt;/strong&gt; — What is &lt;em&gt;Happening&lt;/em&gt; here?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O&lt;/strong&gt; — How does this relate to &lt;em&gt;Our&lt;/em&gt; lives?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;W&lt;/strong&gt; — &lt;em&gt;Why&lt;/em&gt; does this situation exist?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E&lt;/strong&gt; — What can we &lt;em&gt;Do&lt;/em&gt; (Educate, Empower, Act)?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Exhibition as presentation:&lt;/strong&gt; The photographs become an exhibition. This is a complete Gather → Present pathway without a formal Collate stage — the curation of which photographs to display &lt;em&gt;is&lt;/em&gt; the collation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ethical note:&lt;/strong&gt; Photography in schools requires consent. Photographs of identifiable students require specific consent. Photographs of staff require consent. Who appears in an image, and who is conspicuously absent, is itself a finding.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Story Circle&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Oral history / narrative methodology / community organising
&lt;strong&gt;Phase:&lt;/strong&gt; Gather
&lt;strong&gt;Format:&lt;/strong&gt; Small groups of 4–8. Seated in a circle, no hierarchy.
&lt;strong&gt;Time:&lt;/strong&gt; 45–90 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Each person tells a brief story in response to a prompt. No interruptions. No questions during. After all stories are told, the group finds the common threads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prompts for Past movement:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Tell a story about a moment when you felt like a learner — really learning — not necessarily in school.”&lt;/li&gt;
&lt;li&gt;“Tell a story about a time school felt like it was made for someone else.”&lt;/li&gt;
&lt;li&gt;“Tell a story about something you know that school didn’t teach you.”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The no-interruption rule is structural.&lt;/strong&gt; It prevents the loudest voice from shaping the story while it’s being told. Responses come after, in the thread-finding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thread-finding:&lt;/strong&gt; After all stories: “What did we hear in common? What surprised you? What was different?” The facilitator does not lead this — they open it and step back.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;River of Life&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PLA/narrative methodology
&lt;strong&gt;Phase:&lt;/strong&gt; Gather — Past movement specifically
&lt;strong&gt;Format:&lt;/strong&gt; Individual drawing, then paired sharing, then gallery.
&lt;strong&gt;Time:&lt;/strong&gt; 45–60 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Draw your life as a river. The river has tributaries (people and experiences that fed into you), rapids (difficult times, turbulence), still pools (peaceful or formative times), waterfalls (sudden transformations or losses), and a current direction (where the river is going now).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The spatial metaphor does work that prose cannot:&lt;/strong&gt; You do not decide in advance what is a rapid and what is a pool. The drawing decides. Students who have never told anyone about a difficult period of their life will draw rapids and then, looking at what they’ve drawn, find language for it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-cohort version:&lt;/strong&gt; Rivers from three countries displayed together. Where are the rapids? Do they cluster at the same life moments (exam periods, transitions between schools, family disruptions) or at different ones? The comparison is the learning.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Peer Interview&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Participatory Action Research / oral history
&lt;strong&gt;Phase:&lt;/strong&gt; Gather
&lt;strong&gt;Format:&lt;/strong&gt; Pairs, rotating roles. Each person is both interviewer and interviewee.
&lt;strong&gt;Time:&lt;/strong&gt; 20–30 minutes per direction&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Structured interview between students, using a checklist (not a questionnaire). The horizontal relationship between students (as opposed to adult-to-student) changes what is possible. Students often tell each other things they would not tell a facilitator.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Facilitation note:&lt;/strong&gt; Brief the interviewers on the checklist, the open-question principle (What? Why? How?), and the importance of silence — leaving space after an answer before asking the next question. The silence is where the real answer often lives.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Learning Journal / Field Notes&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Action Research / ethnographic practice
&lt;strong&gt;Phase:&lt;/strong&gt; Gather (ongoing throughout)
&lt;strong&gt;Format:&lt;/strong&gt; Individual, ongoing. Can be written, drawn, voice-recorded.
&lt;strong&gt;Time:&lt;/strong&gt; 5–10 minutes at end of each session minimum&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Each participant (students and facilitators) keeps an ongoing record of what they notice, what surprises them, what they don’t understand yet, and what they want to return to. This is not a formal document — it is a thinking tool.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In LFTI:&lt;/strong&gt; Every block node can have a learning journal entry associated with it. The journal is the raw Gather data that hasn’t yet been through Collate.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Timeline&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PLA/oral history tradition
&lt;strong&gt;Phase:&lt;/strong&gt; Gather — Past movement
&lt;strong&gt;Format:&lt;/strong&gt; Group or individual. Physical line on floor or drawn on paper.
&lt;strong&gt;Time:&lt;/strong&gt; 30–45 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Map significant events on a timeline. Can be personal (your own life), institutional (this school’s history), or community (what has happened in this place). Events are placed in sequence and can be annotated with feelings, significance, who was affected.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In LFTI:&lt;/strong&gt; A personal timeline alongside a school’s institutional timeline can reveal the points at which individual students’ lives and institutional decisions intersected — and the places they didn’t, where the school was completely unaware of what was happening to its students.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Focus Group&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Social research / PRA tradition
&lt;strong&gt;Phase:&lt;/strong&gt; Gather
&lt;strong&gt;Format:&lt;/strong&gt; Groups of 6–12, ideally homogeneous (same year group, same gender, same experience). Two facilitators.
&lt;strong&gt;Time:&lt;/strong&gt; 60–90 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Facilitated discussion around a set of open questions. The group dynamic generates responses that individual interviews don’t — agreement, contradiction, negotiation, surprise. The interactions between participants are as informative as the content of what they say.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disaggregation note:&lt;/strong&gt; Mixed groups often produce dominant-voice responses. Consider single-gender groups, or groups separated by year group, confidence level, or experience. The students who never speak in mixed groups will speak in homogeneous ones.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;COLLATE PHASE TOOLS&lt;/h2&gt;
&lt;h3&gt;Collaborative Prioritisation (tool category)&lt;/h3&gt;
&lt;p&gt;The following tools all serve the same purpose: helping a group find shared priorities without imposing an external ranking. Each has different dynamics. Choose based on the group, the context, and what kind of social process is appropriate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The underlying principle:&lt;/strong&gt; Prioritisation is a social act, not a calculation. The goal is not to find the “correct” answer but to make the group’s collective judgment visible to itself.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Stones in Circles (Resource Allocation / Proportional Weighting)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA field practice / Kamoto community methodology
&lt;strong&gt;Phase:&lt;/strong&gt; Collate
&lt;strong&gt;Format:&lt;/strong&gt; Facilitator-run, single shared display. Group sizes of 8–30.
&lt;strong&gt;Time:&lt;/strong&gt; 20–40 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; The facilitator draws or places circles on a shared surface (ground, floor, whiteboard, paper). Each circle represents an option or priority identified during Gather. Each participant is given a fixed number of tokens (stones, coins, dots, votes — the physical material matters: stones are visible, weighty, and cannot be taken back easily). Participants distribute their tokens across the circles according to their priorities. They may put all tokens in one circle or spread them. The distribution is visible to the whole group as it develops.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The social dynamic is the methodology:&lt;/strong&gt; Seeing others place their tokens is generative. It prompts reflection, reconsideration, and sometimes courage — to put your tokens somewhere unexpected, or to hold back from the obvious choice. This is not a bias to be eliminated. It is the collective sense-making process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The visibility question:&lt;/strong&gt; On shared devices vs. a shared physical display, the dynamic changes significantly. A physical display (stones on the ground, visible to everyone in the circle) preserves the social dimension. Individual devices (digital voting) produces cleaner data but a different social experience. The physical version is primary; digital is a secondary option.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Facilitator-run single screen:&lt;/strong&gt; The facilitator distributes tokens on screen based on participants’ verbal or hand-raised instructions. Everyone watches. This is the recommended digital implementation — it preserves the social visibility without requiring individual devices or network connectivity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt; A weighted distribution. Not a winner — a picture of where the group’s attention and energy sits. Multiple circles with roughly equal weight is as informative as one dominant circle.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Matrix Ranking&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA/PLA tradition (AFCAP)
&lt;strong&gt;Phase:&lt;/strong&gt; Collate
&lt;strong&gt;Format:&lt;/strong&gt; Group. Drawn on ground with stick, or on paper/whiteboard.
&lt;strong&gt;Time:&lt;/strong&gt; 30–45 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; A grid with options across the top and criteria down the side. Each cell is filled with tally marks (or stones, or dots) indicating how well this option performs against this criterion. The matrix is built by the group together, not filled in by the facilitator.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In LFTI:&lt;/strong&gt; Useful for evaluating possible responses, interventions, or changes identified during Gather. “Which of these things would make school better?” × “Cost / Feasibility / Student control / Impact.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The tally mark version is intentionally non-numeric:&lt;/strong&gt; Seeing IIIII vs II is different from seeing 5 vs 2. The visual weight of marks carries more than the number.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Pairwise Ranking&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA/PLA tradition (AFCAP)
&lt;strong&gt;Phase:&lt;/strong&gt; Collate
&lt;strong&gt;Format:&lt;/strong&gt; Group or small group. Paper or ground.
&lt;strong&gt;Time:&lt;/strong&gt; 20–30 minutes for up to 6 items&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Given a list of items, compare each pair: which of these two matters more? After all pairs are compared, count the wins. The ranking emerges from the comparisons, not from asking people to rank directly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why it works better than direct ranking:&lt;/strong&gt; Direct ranking (“put these in order”) produces a list that reflects what people think they should say. Pairwise comparison (“just these two — which one?”) surfaces genuine preferences by reducing the cognitive load and the social performance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Limitation:&lt;/strong&gt; Works for small lists (up to 6–8 items). Becomes unwieldy with more.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Body Voting / Human Spectrum&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PLA / community organising / Theatre for Development
&lt;strong&gt;Phase:&lt;/strong&gt; Collate
&lt;strong&gt;Format:&lt;/strong&gt; Whole group, standing. Requires floor space.
&lt;strong&gt;Time:&lt;/strong&gt; 10–20 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; A line is established between two poles (Agree / Disagree, This / That, Important / Not Important). A statement or image is presented. Participants position themselves on the line according to their view. No discussion during positioning. After everyone has placed themselves, the facilitator asks people at different points on the line to explain their position.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why it is powerful:&lt;/strong&gt; You can see the distribution of the whole group at once. You cannot hide — you must take a position. Students who would not raise their hand will walk to a point on a line. The physical commitment is lower but the visibility is higher.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In LFTI:&lt;/strong&gt; Particularly useful for surfacing disagreement within a group — and for making visible that disagreement is not a problem but a feature. “Look — we are not all in the same place on this. That is interesting. Why?”&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Affinity Grouping / Card Sorting&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Design thinking / PLA tradition
&lt;strong&gt;Phase:&lt;/strong&gt; Collate
&lt;strong&gt;Format:&lt;/strong&gt; Group. Physical cards or sticky notes on a wall or floor.
&lt;strong&gt;Time:&lt;/strong&gt; 30–45 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; All Gather artefacts (or summaries of them) are written on individual cards. The group arranges the cards into clusters based on similarity, without predefined categories. Categories emerge from the clustering. The group then names each cluster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The naming act is critical:&lt;/strong&gt; The name the group chooses for a cluster is their analysis of what those things have in common. It often surprises people. It often produces a word or phrase that becomes the organising concept for the Present.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Digital version:&lt;/strong&gt; Cards as nodes in the system, grouped by the group’s decision into synthesis nodes. The physical version is preferable for the initial grouping — the act of moving cards by hand is part of the thinking.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Venn Diagram (Actual / Ideal pair)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA/PLA tradition (AFCAP, Chambers)
&lt;strong&gt;Phase:&lt;/strong&gt; Collate
&lt;strong&gt;Format:&lt;/strong&gt; Group drawing. On ground, floor, paper.
&lt;strong&gt;Time:&lt;/strong&gt; 30–45 minutes per diagram; 60–90 minutes for the pair&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Draw circles representing institutions, people, or forces that affect the group’s experience. Circle size represents significance/importance. Distance between circles represents interaction — circles that touch or overlap have strong interaction; circles that are far apart have little.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The actual/ideal pair:&lt;/strong&gt; Draw the current situation first (actual). Then draw what you wish it looked like (ideal). The gap between the two is the analysis. The circles that have moved, changed size, or changed relationship between the two versions are where the group’s energy lives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In LFTI Situation movement:&lt;/strong&gt; “Draw the people and institutions that affect your experience of school.” Then: “Draw what you wish it looked like.” The student body, the teacher, the headteacher, the government, the family, the curriculum — where are they now? Where should they be?&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Causal Flow Diagram&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA/PLA tradition (AFCAP)
&lt;strong&gt;Phase:&lt;/strong&gt; Collate
&lt;strong&gt;Format:&lt;/strong&gt; Group. On ground or paper with sticks/markers.
&lt;strong&gt;Time:&lt;/strong&gt; 45–60 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Starting from a central problem identified during Gather, the group maps causes (flowing in) and effects (flowing out). Causes of causes. Effects of effects. The diagram grows outward. Eventually the group can see the structure of the problem — which causes are roots (far upstream) and which are symptoms (close to the centre).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The blue/green coding (from AFCAP):&lt;/strong&gt; Blue nodes are causes. Green nodes are effects. This visual distinction makes the structure of the problem legible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In LFTI:&lt;/strong&gt; “What causes school to feel the way it does?” The diagram will show root causes (policy, funding, teacher training, cultural expectations) and proximate causes (class size, timetabling, assessment pressure) and effects (disengagement, anxiety, boredom, exclusion). The group can then ask: where in this diagram do we have leverage?&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Spectrum Line (Two Poles)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PLA / facilitation practice
&lt;strong&gt;Phase:&lt;/strong&gt; Collate
&lt;strong&gt;Format:&lt;/strong&gt; Physical line or drawn continuum. Individual positioning.
&lt;strong&gt;Time:&lt;/strong&gt; 15–25 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Place two opposing concepts at either end of a line. Participants place a Gather finding, idea, or statement on the spectrum between the poles. The placement is their analysis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example poles for LFTI:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Within our control ←→ Outside our control&lt;/li&gt;
&lt;li&gt;This happened to us ←→ We chose this&lt;/li&gt;
&lt;li&gt;School caused this ←→ We brought this with us&lt;/li&gt;
&lt;li&gt;This is about Past ←→ This is about Futures&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The spectrum is not a ranking — it is a relationship.&lt;/strong&gt; Things placed near the centre are genuinely ambiguous. That ambiguity is valuable.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Most Significant Change&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Rick Davies / participatory monitoring and evaluation tradition
&lt;strong&gt;Phase:&lt;/strong&gt; Collate (end of cycle) / Present
&lt;strong&gt;Format:&lt;/strong&gt; Individual reflection first, then group.
&lt;strong&gt;Time:&lt;/strong&gt; 30–45 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; At the end of a cycle, each participant identifies the most significant change they observed or experienced, and why they think it is the most significant. These stories are shared in a group. The group then discusses which change story they find most significant, and why.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The “why” is more important than the “what.”&lt;/strong&gt; The criteria by which people judge significance tells you more than the changes themselves.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In LFTI:&lt;/strong&gt; Run at the end of each movement’s Present phase. “What is the most significant change in how you understand your own experience of school, since we started?” The meta-reflection on the methodology itself is part of the data.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Synthesis Node (Placeholder)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; To be developed
&lt;strong&gt;Phase:&lt;/strong&gt; Collate
&lt;strong&gt;Format:&lt;/strong&gt; TBD
&lt;strong&gt;Description:&lt;/strong&gt; A shared surface on which a group produces a collective representation that did not exist in any single Gather artefact. The synthesis is not a summary — it is a new thing that only the group could make. It may be a composite map, a collective body map, a jointly produced narrative, a scored diagram.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This node is a placeholder.&lt;/strong&gt; The synthesis canvas is the most technically complex piece of the Collate phase and is deferred to a later development cycle. What exists now: a synthesis node can hold images, text, and relations to the Gather artefacts it draws from. The collaborative creation tool does not exist yet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The synthesis output is itself a node&lt;/strong&gt; with &lt;code&gt;feeds&lt;/code&gt; relations to Present and to Whole → Gather.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Triangulation Check&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA/PLA tradition
&lt;strong&gt;Phase:&lt;/strong&gt; Collate (final step before Present)
&lt;strong&gt;Format:&lt;/strong&gt; Facilitator-led reflection with the group.
&lt;strong&gt;Time:&lt;/strong&gt; 20–30 minutes&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Before moving to Present, ask: what did multiple methods tell us? Where did the body maps, transect walks, story circles, and interviews agree? Where did they contradict? The contradictions are not problems — they are the most interesting findings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Questions:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which findings appeared in more than one method?&lt;/li&gt;
&lt;li&gt;Which findings appeared in only one method — and why might that be?&lt;/li&gt;
&lt;li&gt;Whose voice is missing from what we’ve gathered?&lt;/li&gt;
&lt;li&gt;What would we need to gather to be more confident in what we’re seeing?&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;PRESENT PHASE TOOLS&lt;/h2&gt;
&lt;h3&gt;Live Performance&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Theatre for Development / Kamoto Community Arts / Augusto Boal
&lt;strong&gt;Phase:&lt;/strong&gt; Present
&lt;strong&gt;Format:&lt;/strong&gt; Performed to an audience. Audience may be passive (theatre) or active (forum theatre).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Variants:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Forum Theatre (Boal):&lt;/strong&gt; A scene is performed showing a problem. At a key moment, the action is frozen. The facilitator (Joker) asks the audience: what should happen next? Audience members can replace an actor and try a different response. The scene runs again, differently. There is no correct answer — only the exploration of possibilities. The audience are spect-actors, not spectators.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Image Theatre (Boal):&lt;/strong&gt; Participants make frozen images with their bodies — a sculpture showing “how it is” and then a second showing “how it could be.” No words. The images are read and discussed. A non-verbal version of the Venn actual/ideal pair, but embodied. Works across language barriers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Verbatim Theatre:&lt;/strong&gt; The performers speak the exact words gathered during Gather (from interviews, story circles, peer interviews). Nothing invented. The power comes from recognising: these are real words, said by real people, about real experience.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Music / song:&lt;/strong&gt; An original song, or an existing song with new words, performing the findings of Gather. Kamoto’s tradition includes music as a primary vehicle for community reflection.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dance / movement piece:&lt;/strong&gt; Choreographed or improvised movement expressing the findings. The body that was mapped in Gather becomes the instrument of presentation.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Transect Walk as Presentation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; PRA/PLA tradition (Episcopal Relief &amp;amp; Development)
&lt;strong&gt;Phase:&lt;/strong&gt; Present
&lt;strong&gt;Format:&lt;/strong&gt; Participants lead an audience along the route they walked during Gather.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; The participants become guides. They lead community members, other cohorts, or decision-makers along the transect route, stopping at each zone to narrate what they found, what they observed, what they felt. The walk is the report. The audience experiences the space in the same sequence the students experienced it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-cohort version:&lt;/strong&gt; A UK cohort presents their school transect to a Zambian cohort over video. Each stop on the walk is a node that can be viewed and responded to asynchronously. The comparison between two school transects is a cross-cohort interchange in itself.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Exhibition&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Participatory Photography / visual arts practice
&lt;strong&gt;Phase:&lt;/strong&gt; Present
&lt;strong&gt;Format:&lt;/strong&gt; Displayed artefacts in a shared space, physical or digital.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Physical exhibition:&lt;/strong&gt; Body maps, transect diagrams, photographs, drawings displayed on walls or ground. The gallery walk (audience in silence first, then response) is the viewing methodology.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Digital exhibition:&lt;/strong&gt; Images and text displayed as nodes in the spine, with the &lt;code&gt;_visibility: portal&lt;/code&gt; flag marking them for eventual public display.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Audience response:&lt;/strong&gt; Leave response cards, sticky notes, or a response book. The audience’s response to the exhibition is itself Gather material for the next cycle.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Short Video&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Contemporary student communication / digital media
&lt;strong&gt;Phase:&lt;/strong&gt; Present
&lt;strong&gt;Format:&lt;/strong&gt; Individual or small group produced. Phone camera sufficient.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TikTok / Reels format (60–90 seconds):&lt;/strong&gt; The constraint is generative. You cannot explain everything. You must choose. What is the one thing this student wants to say about their experience of school? The constraint forces the kind of clarity that longer forms allow you to avoid.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Documentary format (5–15 minutes):&lt;/strong&gt; More space for complexity. Interview-based or observational. Students as directors, camera operators, and subjects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The channel as ongoing Present:&lt;/strong&gt; A project channel (YouTube, Instagram, TikTok, or private equivalent) that accumulates content over the life of the project is not a single artefact — it is a living Present. Each contribution is a block node. The channel is a session node with an open window.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-cohort exchange:&lt;/strong&gt; A UK student’s 60-second video about their school morning alongside a Zambia student’s 60-second video about their school morning. Same form, same constraint, genuinely comparable.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Podcast / Audio&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Contemporary media / oral history tradition
&lt;strong&gt;Phase:&lt;/strong&gt; Present
&lt;strong&gt;Format:&lt;/strong&gt; Recorded conversation, interview, or narration. Phone mic sufficient.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interview format:&lt;/strong&gt; One student interviews another using the semi-structured checklist approach. The audio is the artefact.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Story format:&lt;/strong&gt; A student narrates their own story directly to the microphone. No interviewer. The intimacy of audio — you are in someone’s ear — produces a different kind of listening than reading or watching.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-cohort exchange:&lt;/strong&gt; Audio messages exchanged between cohorts before video exchange is possible. Lower bandwidth requirement. Can be asynchronous.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Zine / Photo Essay&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; DIY publishing / participatory photography / youth arts
&lt;strong&gt;Phase:&lt;/strong&gt; Present
&lt;strong&gt;Format:&lt;/strong&gt; Printed or digital. Individual or collective.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; A short, self-published document combining image and text. No professional production required. A phone photograph with a handwritten caption is sufficient. The zine form has a long tradition of giving voice to those without access to mainstream publishing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Collective zine:&lt;/strong&gt; Each student contributes one page. The collection is the publication. Print and distribute within the school. Send copies to partner schools.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Story of Self&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Marshall Ganz / community organising tradition
&lt;strong&gt;Phase:&lt;/strong&gt; Present (but also a Gather tool for building narrative)
&lt;strong&gt;Format:&lt;/strong&gt; Individual narrative, structured. 3–5 minutes to tell.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three elements:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Story of Self&lt;/strong&gt; — why I was called to this. A moment that shaped who I am and what I care about.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Story of Us&lt;/strong&gt; — what we share. What brought this group together. What we hold in common.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Story of Now&lt;/strong&gt; — the challenge we face. Why this moment. What is at stake. What we are called to do.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;In LFTI Present:&lt;/strong&gt; A student telling the story of why this project mattered to them, using this structure, to another cohort or to a wider audience. Personal but not private. Specific but universal.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Pre-perceptions Delta (Evaluation Reveal)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Green Living Movement / LFTI methodology
&lt;strong&gt;Phase:&lt;/strong&gt; Present (Whole cycle — final)
&lt;strong&gt;Format:&lt;/strong&gt; Individual reflection + group sharing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Students retrieve their original pre-perceptions instrument. They complete a second version alongside the first. Then they share: what changed? What didn’t? What surprised you about what stayed the same?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is the primary evaluation measure of the whole project.&lt;/strong&gt; Not a test of knowledge acquired but a record of perception changed — or not changed, which is equally interesting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The unchanged perception is as valuable as the changed one.&lt;/strong&gt; If a Bristol student’s assumption about Zambian students is exactly the same after six months of exchange as before, that is the most important finding of all.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;CROSS-CUTTING TOOLS&lt;/h2&gt;
&lt;h3&gt;(Tools that appear in multiple phases)&lt;/h3&gt;
&lt;h3&gt;Hot Seating&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Origin:&lt;/strong&gt; Drama in Education / Theatre for Development
&lt;strong&gt;Phase:&lt;/strong&gt; Gather (generating stories) / Present (performing them)
&lt;strong&gt;Format:&lt;/strong&gt; One participant in role, group asks questions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; A participant takes on a role — themselves at a different age, a character from their story, a figure of authority in their school. The group asks questions. The person in role answers as that character. The role distance is protective — you are not speaking as yourself, so you can say things that would be harder to say directly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In LFTI:&lt;/strong&gt; A student in role as their year-3 self, being asked about their first experience of school. Or a student in role as their headteacher, being asked why the rules are what they are. The role-play surfaces knowledge that direct questions don’t reach.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Learning Journal (ongoing)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Phase:&lt;/strong&gt; All phases
&lt;strong&gt;See Gather phase entry above.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;PROVENANCE NOTES&lt;/h2&gt;
&lt;p&gt;Several tools in this library have specific origins that must be honoured:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kamoto Community Arts / George Daka, Phillip Kaluba, Mary Manzole:&lt;/strong&gt;
The Body Map facilitation protocol, the Participatory Performance Practice (PPP) framework, and the community arts methodology that underlies LFTI’s approach to the body as instrument. These tools originate in Zambia. When used by LFTI, they are used with permission and in partnership — not borrowed or adapted without acknowledgement.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Green Living Movement / Emmanuel Mutambashiku:&lt;/strong&gt;
The Pre-perceptions instrument. Used throughout LFTI as the primary evaluation mechanism.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Augusto Boal / Theatre of the Oppressed:&lt;/strong&gt;
Forum theatre, image theatre, the spect-actor concept. A formal body of work with its own literature, training tradition, and ethical framework. Facilitators using these tools should have specific training.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Robert Chambers / PRA tradition:&lt;/strong&gt;
Handing over the stick, triangulation, sitting down, optimal ignorance. These principles are widely documented but originate in a specific methodological tradition that deserves citation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wang &amp;amp; Burris / PhotoVoice:&lt;/strong&gt;
The SHOWED methodology and the participatory photography framework.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marshall Ganz / Harvard Kennedy School:&lt;/strong&gt;
Story of Self / Story of Us / Story of Now. Developed in the context of community organising; applies directly to LFTI’s Present phase.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;SEEDING INSTRUCTIONS FOR CLAUDE CODE&lt;/h2&gt;
&lt;p&gt;When seeding the reference instance from this document:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Each &lt;code&gt;###&lt;/code&gt; heading under a phase becomes a &lt;strong&gt;tool node&lt;/strong&gt; with &lt;code&gt;type: &amp;quot;tool&amp;quot;&lt;/code&gt; and &lt;code&gt;meta._level: &amp;quot;reference&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each phase heading (GATHER, COLLATE, PRESENT) becomes a &lt;strong&gt;cycle phase node&lt;/strong&gt; with &lt;code&gt;meta.phase&lt;/code&gt; set accordingly.&lt;/li&gt;
&lt;li&gt;The PRINCIPLES &amp;amp; ETHOS section becomes a &lt;strong&gt;methodology node&lt;/strong&gt; above the phase nodes, with &lt;code&gt;contains&lt;/code&gt; relations to each principle node.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Variants&lt;/strong&gt; listed under a tool become &lt;strong&gt;block nodes&lt;/strong&gt; under the tool node, with &lt;code&gt;sequence&lt;/code&gt; relations between them where order matters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Facilitation steps&lt;/strong&gt; go in the node body, not as child nodes — they are content, not structure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provenance notes&lt;/strong&gt; become &lt;code&gt;involves&lt;/code&gt; relations pointing to the relevant institution nodes (Kamoto, GLM, etc.) already seeded in the main LFTI tree.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Placeholder nodes&lt;/strong&gt; (Synthesis) get &lt;code&gt;meta._placeholder: true&lt;/code&gt; and a body noting what is deferred and why.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-cohort versions&lt;/strong&gt; of tools get &lt;code&gt;meta.context: [&amp;quot;cross-cohort&amp;quot;]&lt;/code&gt; and a &lt;code&gt;responds_to&lt;/code&gt; relation placeholder.&lt;/li&gt;
&lt;li&gt;All reference instance nodes get &lt;code&gt;meta._visibility: &amp;quot;partners&amp;quot;&lt;/code&gt; — visible to collaborating institutions, not public.&lt;/li&gt;
&lt;li&gt;The Body Map node gets a specific note: &lt;code&gt;meta._facilitation_owner: &amp;quot;Kamoto/Mary Manzole&amp;quot;&lt;/code&gt; and &lt;code&gt;meta._status: &amp;quot;protocol_pending&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  <entry>
    <title>The Spine — generic architecture, and how to reseed it</title>
    <link href="https://themetalevel.org/notes/spine-architecture/"/>
    <updated>2026-08-12T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/spine-architecture/</id>
    <summary>LFTI is a small general-purpose node graph editor with a participatory education seed planted in it. Which parts are spine, which are seed, and how to replant the essence elsewhere.</summary>
    <content type="html">&lt;p&gt;Written 2026-08-12, from the state of the codebase at that date.&lt;/p&gt;
&lt;p&gt;LFTI is not really an app about participatory education. It is a small
general-purpose &lt;strong&gt;node graph editor&lt;/strong&gt; — the spine — with a participatory
education &lt;strong&gt;seed&lt;/strong&gt; planted in it. Everything domain-specific grew from that
seed. The point of this note is to name which parts are the spine and which
are the seed, so the same essence can be replanted in another domain without
re-deriving it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. What the spine actually is&lt;/h2&gt;
&lt;p&gt;The generic layer is small. Roughly 460 lines of server and a few thousand of
client:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Piece&lt;/th&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;What it gives you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node CRUD&lt;/td&gt;
&lt;td&gt;&lt;code&gt;api/nodes.js&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;one table, one shape, recursive delete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage + visibility&lt;/td&gt;
&lt;td&gt;&lt;code&gt;db/database.js&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SQLite, relation index, role filter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;&lt;code&gt;api/auth.js&lt;/code&gt;, &lt;code&gt;middleware/auth.js&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;sessions, roles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attachments&lt;/td&gt;
&lt;td&gt;&lt;code&gt;api/images.js&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;files on any node&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Views&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lfti.js&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;tree / position / graph, capture, relations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Everything else — projects, cycles, phases, tools, classes, groups — is seed.&lt;/p&gt;
&lt;h3&gt;The one data structure&lt;/h3&gt;
&lt;p&gt;Every single thing in the system is a row in &lt;code&gt;nodes&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;id · parent_id · title · body · type · tags · created_at · updated_at · meta · relations
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the whole schema for content. There is no projects table, no classes
table, no tools table. &lt;code&gt;type&lt;/code&gt; is a free string, &lt;code&gt;meta&lt;/code&gt; is free-form JSON, and
&lt;code&gt;relations&lt;/code&gt; is a JSON array of &lt;code&gt;{ id, type, target, label }&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is the central bet, and it is the thing worth copying.&lt;/strong&gt; A new domain
concept costs you a new &lt;code&gt;type&lt;/code&gt; string and some &lt;code&gt;meta&lt;/code&gt; keys — no migration, no
new endpoint, no schema change. The cost is paid later, in that nothing is
enforced: every invariant lives in code and can drift. Both halves of that
trade showed up in LFTI and are documented in §4.&lt;/p&gt;
&lt;h3&gt;Two axes, deliberately&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;parent_id&lt;/code&gt;&lt;/strong&gt; — the containment tree. Exactly one parent. This is what the
left-hand tree renders and what recursive delete follows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;relations[]&lt;/code&gt;&lt;/strong&gt; — a directed graph over the same nodes, many-to-many,
typed. In LFTI: &lt;code&gt;contains, involves, references, sequence, feeds, hosts&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Almost every interesting question (“what feeds this?”, “what does this
reference?”) is a graph question, while navigation and lifecycle are tree
questions. Keeping both, and being clear which is which, is most of the
architecture. &lt;code&gt;relations_index&lt;/code&gt; is just a denormalised copy of &lt;code&gt;relations[]&lt;/code&gt;
for querying in the other direction.&lt;/p&gt;
&lt;h3&gt;Levels — reference vs instance&lt;/h3&gt;
&lt;p&gt;One &lt;code&gt;meta&lt;/code&gt; key does an enormous amount of work: &lt;code&gt;_level&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;_level: &#39;reference&#39;&lt;/code&gt; — canonical, authored-once methodology. The 33 tool
definitions. Read-mostly, visible to everyone, never owned by a school.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_level: &#39;instance&#39;&lt;/code&gt; — a live running thing. A project, a class doing a tool
on a Tuesday, a contribution.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An instance points at its reference with a &lt;code&gt;references&lt;/code&gt; relation and copies
what it needs to vary. That single distinction is what lets one body of
methodology serve many cohorts without either drifting into the other. &lt;strong&gt;If
you reseed, keep this.&lt;/strong&gt; It is the most transferable idea in the codebase.&lt;/p&gt;
&lt;h3&gt;Visibility as a pure function&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;filterNodesByVisibility(nodes, user)&lt;/code&gt; takes the whole node set and a user and
returns what they may see, by these rules in order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;superadmin sees everything&lt;/li&gt;
&lt;li&gt;anyone authenticated sees &lt;code&gt;_level: &#39;reference&#39;&lt;/code&gt; or &lt;code&gt;_visibility: &#39;public&#39;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_visibility: &#39;portal&#39;&lt;/code&gt; is visible to any authenticated user&lt;/li&gt;
&lt;li&gt;a node whose &lt;code&gt;meta.institution_id&lt;/code&gt; matches the user’s&lt;/li&gt;
&lt;li&gt;anything under the user’s institution by walking &lt;code&gt;parent_id&lt;/code&gt; upward&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The client then fetches the whole visible set in one call and renders from
memory. That is why the app feels instant and why the tree, graph and
position views are cheap — they are all just projections of one in-memory map.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The limit of that design:&lt;/strong&gt; the client holds everything it is allowed to
see, so any UI-side role switching is cosmetic. LFTI’s “view as” switcher is
explicitly a preview, not a permission test, for exactly this reason.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2. What the seed is&lt;/h2&gt;
&lt;p&gt;The domain layer, in dependency order, is about 1,700 lines of server:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;institutions (126)  →  projects (451)  →  tool-instances (349)
                                       →  class-instances (648)
                          token-login (80)   filter-options (69)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And a vocabulary of types layered on the generic node:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;institution → container → project → cycle → session → tool_instance
                                          → class_instance → group_instance
                                                           → artefact
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Plus &lt;code&gt;tool&lt;/code&gt; (reference), &lt;code&gt;class&lt;/code&gt;, &lt;code&gt;person&lt;/code&gt;, &lt;code&gt;block&lt;/code&gt;, &lt;code&gt;exchange&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Nothing in the spine knows any of these words. They are conventions the domain
routes agree on. You could delete every file in &lt;code&gt;api/&lt;/code&gt; except &lt;code&gt;nodes.js&lt;/code&gt;,
&lt;code&gt;auth.js&lt;/code&gt; and &lt;code&gt;images.js&lt;/code&gt; and still have a working generic outliner.&lt;/p&gt;
&lt;h3&gt;How the seed gets planted&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;seedLFTI()&lt;/code&gt; is a plain function that builds a node map, extracted from source
at boot and run in a sandbox when the database is empty. The methodology comes
in as data, not as schema. That is why the tools could be re-tagged wholesale
(&lt;code&gt;produces&lt;/code&gt; / &lt;code&gt;consumes&lt;/code&gt;) via one idempotent migration script without touching
a single table definition.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3. Roadmap for a new seed&lt;/h2&gt;
&lt;p&gt;If you wanted to plant a different domain in the same spine, this is the order
that would have saved LFTI the most rework. Roughly the order it happened,
with the mistakes taken out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 0 — decide the vocabulary before writing code.&lt;/strong&gt;
Write the type list and the relation list as a flat document. For each type:
is it reference or instance? What is its parent? What does it point at? An
afternoon here is worth weeks later. LFTI’s single most expensive defect — two
rival “class” entities, one under the project and one under the school —
is a Phase 0 omission, and it was still blocking work months later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1 — spine only.&lt;/strong&gt; Node CRUD, tree view, capture, relations, delete.
No domain words at all. You should be able to build an arbitrary outline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 2 — auth and visibility.&lt;/strong&gt; Roles, sessions, and the visibility
function. Do this &lt;em&gt;before&lt;/em&gt; the domain, because visibility rules shape what
the domain is allowed to assume. Write the role ladder down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3 — the reference layer.&lt;/strong&gt; Author the canonical content as a seed
function: your equivalent of the 33 tools. Mark it &lt;code&gt;_level: &#39;reference&#39;&lt;/code&gt; and
&lt;code&gt;_visibility: &#39;public&#39;&lt;/code&gt;. Resist adding instance concepts here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 4 — one instance chain, end to end, for one user.&lt;/strong&gt;
Pick the single most important path — for LFTI: institution → project →
phase → tool instance → group → contribution — and build it all the way
through for one role. Do not build breadth. A chain that works end to end
tells you more about the model than five half-built layers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 5 — the second actor.&lt;/strong&gt; Add the role that consumes what the first
produces (teacher watching students). This is where the model gets tested,
because it forces the question of what rolls up and what stays local.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 6 — the working surface.&lt;/strong&gt; The page the end user actually touches,
with its own affordances. LFTI got here late: group pages existed for months
as bare contribution lists before becoming worksheets, so nothing could
actually be run in a classroom.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 7 — feedback and learning.&lt;/strong&gt; Only once real usage exists. Anything
that learns from history needs history, and history needs the working
surface from Phase 6 to have been used in anger.&lt;/p&gt;
&lt;h3&gt;Three ordering lessons, dearly bought&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Write side before read side.&lt;/strong&gt; LFTI rendered “in progress · step 3” and
stuck-timer warnings in seven places for months while nothing ever wrote a
step trace. The display was finished and the data never arrived. Build the
writer first, even if it is ugly, then the readers have something true to
render.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gate on the thing the user actually produces.&lt;/strong&gt; The step-completion gate
was first built against a separate step-tagged contribution, which meant
nothing the user naturally did could unlock it. Moving the gate to the note
in the worksheet — the thing they were already typing — made it work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A feature with no entry point does not exist.&lt;/strong&gt; The &lt;code&gt;responds_to&lt;/code&gt;
relation, the whole cross-phase feed-forward mechanism, was fully built on
both sides and had &lt;em&gt;zero&lt;/em&gt; instances in the database because the button was
somewhere nobody went.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;4. Where the flat model bites&lt;/h2&gt;
&lt;p&gt;Worth knowing in advance, because all of these are consequences of the schema
bet in §1 and every one of them cost real time here.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nothing is enforced.&lt;/strong&gt; &lt;code&gt;meta.institution_id&lt;/code&gt; may be a slug (&lt;code&gt;&#39;uk&#39;&lt;/code&gt;) or a
node id (&lt;code&gt;&#39;inst_uk_schools&#39;&lt;/code&gt;) depending on which code path wrote it. Every
reader carries a fallback map. Pick one representation on day one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deletion cascades the tree, not the graph.&lt;/strong&gt; Deleting a node removes its
descendants and its outbound relations, but inbound relations from elsewhere
survive and dangle. Sweep them or accept the debt knowingly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single &lt;code&gt;parent_id&lt;/code&gt; forces a choice the domain may not want.&lt;/strong&gt; A class
genuinely belongs to both a school and a tool run. LFTI resolves this with
&lt;code&gt;class_instance&lt;/code&gt; as a projection of a class into a tool — which works, but
is the kind of thing to decide deliberately rather than discover.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seeds drift from their loader.&lt;/strong&gt; &lt;code&gt;seedLFTI()&lt;/code&gt; moved from the HTML into
&lt;code&gt;lfti.js&lt;/code&gt; and the loader kept reading the HTML, so a fresh database silently
seeded zero nodes for months behind a &lt;code&gt;console.warn&lt;/code&gt;. If a code path only
runs on first boot, it is untested by definition — test it explicitly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docs rot faster than code.&lt;/strong&gt; &lt;code&gt;KNOWN_ISSUES.md&lt;/code&gt; asserted that tool-to-tool
relations already existed in the graph (there were none) and that students
were read-only (they had not been for some time). Design notes describing
intent age badly once they start describing state.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;5. The transferable essence, in one paragraph&lt;/h2&gt;
&lt;p&gt;One node table with a free-form type and JSON meta; a containment tree and a
typed graph over the same nodes; a hard split between authored reference
content and live instances that reference it; visibility as a pure function of
node plus user; and the whole visible graph shipped to the client so views are
just projections. Plant a domain in that as seed data rather than as schema,
build one chain end to end before building breadth, and always build the thing
that writes before the thing that displays.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Mapping the opportunity — how it was built</title>
    <link href="https://themetalevel.org/notes/mapping-the-opportunity-method/"/>
    <updated>2026-08-11T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/mapping-the-opportunity-method/</id>
    <summary>Method, reliability and findings behind the southern England screen</summary>
    <content type="html">&lt;p&gt;Method, reliability and findings behind the southern England screen&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Technical companion note | August 2026&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This note explains how the southern England screen was produced, how far each step can be trusted, and what the resulting numbers do and do not mean. It is written to be argued with: every judgement is named, every weakness stated, and every figure traceable to an open dataset.&lt;/p&gt;
&lt;h2&gt;1. The data&lt;/h2&gt;
&lt;p&gt;Everything used is open, and everything is vector or tabular - there is deliberately no terrain data and no satellite imagery, so the whole analysis runs on an ordinary laptop from about 130 MB of downloads. The study area is Somerset to Kent, the south coast to roughly the Thames: 365 by 140 kilometres.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Dataset&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;What it gives us&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;In our area&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Source&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;EA Hydrology API&lt;/td&gt;
&lt;td&gt;Daily mean river flow, 2015-2025&lt;/td&gt;
&lt;td&gt;374 stations, 1.47M readings&lt;/td&gt;
&lt;td&gt;Environment Agency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BGS 1:625k Hydrogeology&lt;/td&gt;
&lt;td&gt;Which rock is where, and how productive&lt;/td&gt;
&lt;td&gt;2,485 polygons&lt;/td&gt;
&lt;td&gt;BGS / UKRI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WFD Groundwater Bodies&lt;/td&gt;
&lt;td&gt;Regulatory units and their health status&lt;/td&gt;
&lt;td&gt;123 bodies&lt;/td&gt;
&lt;td&gt;Environment Agency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OS Open Rivers&lt;/td&gt;
&lt;td&gt;The river network, and which way it flows&lt;/td&gt;
&lt;td&gt;24,714 links&lt;/td&gt;
&lt;td&gt;Ordnance Survey&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BGS GeoIndex boreholes&lt;/td&gt;
&lt;td&gt;Where holes were drilled, and how deep&lt;/td&gt;
&lt;td&gt;248,516 records&lt;/td&gt;
&lt;td&gt;BGS / UKRI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source Protection Zones&lt;/td&gt;
&lt;td&gt;Groundwater protected for public supply&lt;/td&gt;
&lt;td&gt;1,789 zones&lt;/td&gt;
&lt;td&gt;Environment Agency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSSI / SAC / SPA / Ramsar&lt;/td&gt;
&lt;td&gt;Protected wildlife sites&lt;/td&gt;
&lt;td&gt;2,943 sites&lt;/td&gt;
&lt;td&gt;Natural England&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CaBA Chalk Streams&lt;/td&gt;
&lt;td&gt;Designated chalk stream reaches&lt;/td&gt;
&lt;td&gt;6,372 reaches&lt;/td&gt;
&lt;td&gt;The Rivers Trust&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;2. Turning flow records into a ‘divertible volume’&lt;/h2&gt;
&lt;p&gt;This step produces the headline number, so it deserves the most scrutiny.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The idea.&lt;/strong&gt; You cannot take water from a river whenever you like. An abstraction licence typically says: don’t start pumping until the river runs high, and never draw it below a floor. We applied that shape of rule to every gauge. The trigger is the flow the river exceeds 12.5% of the time - a high flow, below which pumps stay off. The hands-off level is the flow it exceeds 19% of the time, and the river is never drawn below it. On a day above the trigger, the divertible volume is whatever sits between the two, multiplied by the seconds in a day.&lt;/p&gt;
&lt;p&gt;Both thresholds come from each station’s own record, so a small Sussex stream is judged against its own behaviour rather than a regional average. Totals run over water years (October to September) so a winter is never split across two annual figures, and a year counts only if at least 95% complete.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How reliable is it?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Three checks, done rather than assumed. The Thames at Kingston was recalculated from the raw data by separate code sharing nothing with the main pipeline: 431.48 Mm3/yr both ways. The arithmetic reproduces its own definition - days when diversion is allowed should be exactly 12.5% of the record, and across 370 stations the measured figure is 12.43%. And the ‘winter surplus’ claim was tested rather than asserted: the rule contains no season, so nothing forced the answer, yet 92% of divertible volume falls between October and March, and no candidate falls below 88%.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A real problem we found, and fixed&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Environment Agency publishes three daily flow series per station - mean, minimum and maximum - and the field identifying which is which is missing from the API’s search results. Our first run silently pulled the daily minimum for 123 stations and the maximum for 134; only 117 of 374 were correct. The statistic turned out to be recoverable from the series identifier, so it was fixed and everything re-fetched. Anyone reusing that API is exposed to the same trap, and it would not announce itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How this step could be improved&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A drought sensitivity would help most: a ten-year mean hides how far the resource falls in a dry year, which is exactly when stored water is wanted. The two thresholds are inherited from the Somerset work and undefended in this region - they deserve testing. And many stations reach back to the 1960s, which would let variability be separated from trend.&lt;/p&gt;
&lt;h2&gt;3. What was actually analysed&lt;/h2&gt;
&lt;p&gt;Every gauge follows the same sequence. Nothing is weighted and nothing is combined into a single score:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;374 flow gauges → 370 with a usable daily-mean record → 83 clearing 20 Mm3/yr → 73 also within 15 km of a suitable aquifer → collapse to 28 independent river systems → ranked by aquifer tier first, volume second.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The aquifer test has two tiers,&lt;/strong&gt; printed in the output rather than hidden inside a score. Tier 1 is intergranular rock - water moves through the pore spaces between grains, like a sponge, so storage behaves predictably. Here that means Lower Greensand and Triassic sandstone, 1,500 km2 in the study area. Tier 2 is the Chalk, where water moves through cracks: less predictable, but this is the aquifer Britain has actually stored water in, and the North London scheme uses confined Chalk. Tier 1 outranks tier 2 at equal volume.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One exclusion by judgement.&lt;/strong&gt; The Jurassic oolitic limestones pass the tier-2 test on the official classification and were excluded anyway, because our own Somerset boreholes show them behaving differently: the water table at Mells rises and falls 2.37 m a year, against 6.5 to 13.4 m in three Chalk boreholes. They are still drawn on the map, hatched and labelled as excluded, so the judgement can be challenged rather than disappearing into a filter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nesting - the most important step.&lt;/strong&gt; Flow at one gauge already includes everything upstream of it. Kingston measures the same water as Reading and Windsor, and also the Mole and the Wey, which join the Thames under their own names - so grouping by river name would miss every tributary. Instead the Ordnance Survey river network itself was traced: each link knows its start point, end point and flow direction, which establishes exactly which gauge lies downstream of which. The effect is large. Adding all 73 candidates gives 5,446 Mm3/yr; the 28 genuine systems total 1,943. Nearly two thirds of the naive figure is the same water counted repeatedly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three things are reported but never scored:&lt;/strong&gt; groundwater body status, all constraint layers, and borehole evidence. They change how a row reads, not where it sits. Scoring them would mean asserting regulatory and geological judgements this screen has no basis to make.&lt;/p&gt;
&lt;h2&gt;4. The map, and how to read it&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/mapping-the-opportunity-method/mtom-1.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Figure 1. The screen. Full-resolution version supplied separately - the detail rewards zooming.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Blue and pink areas&lt;/strong&gt; are the two aquifer tiers - blue intergranular, pink Chalk. Diagonal hatching is the excluded oolitic limestone. Dotted shading marks groundwater bodies already in poor health.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stars are candidate river systems.&lt;/strong&gt; Colour is the tier; area is proportional to divertible volume, so twice the area means twice the water. Only the largest are labelled, to keep the map legible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Small open circles&lt;/strong&gt; are candidates upstream of a star and already counted inside it. Grey dots are the other 297 gauges, which did not qualify.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A black ring&lt;/strong&gt; means that candidate stands inside a Source Protection Zone or a designated wildlife site.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dark blue lines&lt;/strong&gt; are designated chalk streams; pale blue is the ordinary river network.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What the map does not say.&lt;/strong&gt; Nothing about how much water an aquifer could hold, whether it is covered and able to retain water, or whether anyone would be permitted to do any of this. Blank areas are not ‘no opportunity’ - they are places with no gauge, or a gauge that missed a threshold.&lt;/p&gt;
&lt;h2&gt;5. Findings, and what the numbers mean&lt;/h2&gt;
&lt;p&gt;Top of each tier; the full 28-row table is in the accompanying technical report.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;tier&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;system&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;river&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Mm3/yr&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;subsumes&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;WFD status&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;constraint&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Trews Weir&lt;/td&gt;
&lt;td&gt;Exe&lt;/td&gt;
&lt;td&gt;194.8&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;none of the five&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Allington&lt;/td&gt;
&lt;td&gt;Medway&lt;/td&gt;
&lt;td&gt;141.5&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;td&gt;SPZ 0.5 km&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Bradford on Avon&lt;/td&gt;
&lt;td&gt;Bristol Avon&lt;/td&gt;
&lt;td&gt;112.2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;td&gt;SSSI 0.5 km&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Pallingham&lt;/td&gt;
&lt;td&gt;Arun&lt;/td&gt;
&lt;td&gt;92.2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;outside&lt;/td&gt;
&lt;td&gt;INSIDE SSSI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Crandon Bridge&lt;/td&gt;
&lt;td&gt;King’s Sedgemoor Drain&lt;/td&gt;
&lt;td&gt;81.3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;none of the five&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Kingston&lt;/td&gt;
&lt;td&gt;Thames&lt;/td&gt;
&lt;td&gt;431.5&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;outside&lt;/td&gt;
&lt;td&gt;chalk stream 39 m&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Throop&lt;/td&gt;
&lt;td&gt;Dorset Stour&lt;/td&gt;
&lt;td&gt;115.5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;chalk stream 22 m&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;East Mills Combined&lt;/td&gt;
&lt;td&gt;Hampshire Avon&lt;/td&gt;
&lt;td&gt;92.6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;INSIDE SSSI + SAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Low Hall&lt;/td&gt;
&lt;td&gt;Lee&lt;/td&gt;
&lt;td&gt;41.6&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;outside&lt;/td&gt;
&lt;td&gt;INSIDE SPZ1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Welford&lt;/td&gt;
&lt;td&gt;Lambourn&lt;/td&gt;
&lt;td&gt;40.6&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;td&gt;INSIDE SPZ3, SSSI + SAC&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;What ‘194.8 Mm3/yr’ actually means.&lt;/strong&gt; Over 2015 to 2025, in an average year, 194.8 million cubic metres passed the gauge at Trews Weir above the hands-off flow, on days when the river was above the trigger. It measures how much water was theoretically available to a licence-shaped rule at that point on that river. It is not an amount anyone could take, store or use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The traps, spelt out&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1Never add two rows together.&lt;/strong&gt; Each row already contains everything upstream of it. The 28 rows can be compared, but not summed with their own tributary gauges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2Divertible is not available.&lt;/strong&gt; No pump, pipeline, treatment plant, borehole or aquifer acceptance rate is considered anywhere in this screen. Whether the ground could swallow water at that rate is untested here - and in most real schemes it is the binding constraint.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3’Highly productive aquifer’ says nothing about storage volume.&lt;/strong&gt; It describes how easily water moves through rock - and easy movement is as much a reason water will leave a store as a reason it will enter one. What decides whether a winter’s water is still there in August is confinement: a low-permeability cap above it. The 1:625k map cannot show that, because it maps rock at outcrop - where Chalk lies beneath London Clay, the map shows London Clay. Our Somerset measurements give unconfined Chalk a 41-day drainage half-life.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4Distances are straight lines.&lt;/strong&gt; 15 km on a map is not 15 km of pipeline, and says nothing about the ground in between or who owns it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5A gauge is a measuring point, not a proposed intake.&lt;/strong&gt; It is where somebody chose to put a flow recorder, sometimes decades ago.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6Borehole counts are about evidence, not geology.&lt;/strong&gt; The index carries no rock descriptions, thickness or yield. 808 boreholes near Riverside Park with not one reaching 50 m tells you a lot of shallow construction happened there and nobody drilled for water.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7An empty constraint column means ‘none of these five layers’,&lt;/strong&gt; not ‘unconstrained’. Licensing, existing users, planning, land ownership and flood risk are all absent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;8’Inside’ is tested at the gauge point.&lt;/strong&gt; A scheme is bigger than a gauge; four candidates sit within 10 metres of a boundary without counting as inside it.&lt;/p&gt;
&lt;h2&gt;6. Conclusions&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1The resource is real, and concentrated.&lt;/strong&gt; 28 independent systems clear 20 Mm3/yr, totalling 1,943 Mm3/yr. Kingston alone is 22% of that - one river system is nearly a quarter of the regional opportunity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2Physical opportunity and regulatory difficulty are correlated, not independent.&lt;/strong&gt; Three candidates stand inside a Source Protection Zone 1, the innermost protection ring around a public water supply. That is not bad luck: an SPZ1 exists because the aquifer beneath is productive and already used for supply. The same fact that makes a site score well is what put the zone there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3The tier-2 list and the chalk stream map are nearly the same map.&lt;/strong&gt; Eight candidates sit within 50 metres of a designated chalk stream. The most productive Chalk options are also the most politically exposed freshwater habitat in England.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4Six candidates carry none of the designations we can see,&lt;/strong&gt; led by Trews Weir at 194.8 Mm3/yr - and three of the six are in Somerset.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5Nowhere is unexamined, but depth is scarce.&lt;/strong&gt; Every candidate has boreholes nearby; four have none deeper than 50 m within 2 km. Pallingham is the thinnest - four boreholes, none deep - and is the fourth-largest tier-1 system.&lt;/p&gt;
&lt;h2&gt;7. What Somerset looks like in a regional frame&lt;/h2&gt;
&lt;p&gt;Somerset returns the largest cluster in the screen - and, more surprisingly, some of the least constrained sites in southern England. Of the six candidates region-wide sitting inside no designation at all, three are Somerset.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Somerset system&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;tier&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Mm3/yr&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;rank in tier&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;constraint&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;boreholes &amp;lt;2km (deep)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Crandon Bridge&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;81.3&lt;/td&gt;
&lt;td&gt;5 of 16&lt;/td&gt;
&lt;td&gt;none of the five&lt;/td&gt;
&lt;td&gt;56 (4)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aller Drove Bridge&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;53.1&lt;/td&gt;
&lt;td&gt;7 of 16&lt;/td&gt;
&lt;td&gt;SPA at 10 m&lt;/td&gt;
&lt;td&gt;17 (0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Taunton Market&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;39.4&lt;/td&gt;
&lt;td&gt;8 of 16&lt;/td&gt;
&lt;td&gt;none of the five&lt;/td&gt;
&lt;td&gt;84 (5)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bason Bridge&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;38.5&lt;/td&gt;
&lt;td&gt;9 of 16&lt;/td&gt;
&lt;td&gt;none of the five&lt;/td&gt;
&lt;td&gt;20 (2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pen Mill&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;33.9&lt;/td&gt;
&lt;td&gt;6 of 12&lt;/td&gt;
&lt;td&gt;SPZ at 0.6 km&lt;/td&gt;
&lt;td&gt;101 (18)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chiselborough&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;20.1&lt;/td&gt;
&lt;td&gt;12 of 12&lt;/td&gt;
&lt;td&gt;INSIDE SPZ 2c&lt;/td&gt;
&lt;td&gt;7 (2)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Two specific flags for the local work.&lt;/strong&gt; Chiselborough sits inside a Source Protection Zone (2c) and is part of the nine-gauge inflow set used in the Somerset model, where that constraint is currently not noted anywhere. And Aller Drove Bridge has 17 boreholes within 2 km with none deeper than 50 m - the thinnest evidence of any Somerset candidate. That is an investigation-cost warning, not a geological verdict.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An independent corroboration worth noting.&lt;/strong&gt; The Somerset configuration records, in a hand-written comment, that Taunton Market duplicates the Bishops Hull reach and should not be summed with it. Tracing the Ordnance Survey river network from scratch, with no knowledge of those comments, reached the same conclusion. That points at a cheap and worthwhile next job: run the same tracer over all nine Somerset inflow gauges to verify independently that none contains another. The local model’s inflow total currently rests on hand-written notes; this would either confirm it or correct it, in about half a day.&lt;/p&gt;
&lt;h2&gt;8. Next steps&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What is missing, and whether open data can supply it&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;What is missing&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Can open data fix it?&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Aquifer storage capacity - absent entirely&lt;/td&gt;
&lt;td&gt;Partly. Outcrop area is known; specific yield and usable thickness are not published spatially. A bounded estimate with stated assumptions is possible; real numbers need the BGS Aquifer Properties Manual, which no public service supplies.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confinement - only a crude proxy&lt;/td&gt;
&lt;td&gt;No. The groundwater body dataset has no confinement attribute at all - checked across all 271 bodies in England. It needs borehole logs read by a person, and we now hold 248,516 scan links to read from.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abstraction licences and existing users&lt;/td&gt;
&lt;td&gt;Probably yes. The EA publishes licence data; not yet integrated. This is the biggest missing constraint.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Demand - who actually needs the water&lt;/td&gt;
&lt;td&gt;Yes. Water company resource plans and Water Resource Zones are open. Water far from demand is not an opportunity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How fast an aquifer will accept water&lt;/td&gt;
&lt;td&gt;No. Requires field testing.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Analyses possible with data already held&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Drought sensitivity:&lt;/strong&gt; recompute divertible volume on the three driest water years per station, which answers ‘does this survive a dry decade’ without needing climate projections.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Threshold sweep:&lt;/strong&gt; test whether the 20 Mm3/yr and 15 km cut-offs do real work or simply sit in a gap in the data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distance to demand:&lt;/strong&gt; water far from anyone who needs it is not an opportunity. Water Resource Zones are open data, and this is a genuinely new axis that would reorder the table.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A first-order storage bound for tier 1:&lt;/strong&gt; outcrop area multiplied by a plausible range of specific yield and usable thickness. Crude, but it would let the screen say whether the resource exceeds plausible storage - which is a stronger claim than it currently makes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Borehole log triage:&lt;/strong&gt; the deep holes on aquifer outcrop near each candidate already have scan links attached. The top twenty could be read by a person.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;All code, method and intermediate figures are held in the project repository. Data fetchers are resumable and rate-limited; raw downloads are never modified after collection. Attribution: flow data © Environment Agency, OGL v3. Geology and borehole index © UKRI / BGS. Groundwater bodies, basin districts and Source Protection Zones © Environment Agency, OGL v3. Protected sites © Natural England, OGL v3. Chalk streams © The Rivers Trust. Contains OS data © Crown copyright and database right 2026.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This note was written in Word; the text above is a faithful conversion, and the original is the authoritative copy.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/assets/docs/mapping_the_opportunity_method.docx&quot;&gt;Download the original (.docx)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Read the screen it describes: &lt;a href=&quot;/notes/mapping-the-opportunity/&quot;&gt;Mapping the opportunity&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Mapping the opportunity</title>
    <link href="https://themetalevel.org/notes/mapping-the-opportunity/"/>
    <updated>2026-08-11T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/mapping-the-opportunity/</id>
    <summary>A first-pass screen for seasonal aquifer storage in southern England</summary>
    <content type="html">&lt;p&gt;A first-pass screen for seasonal aquifer storage in southern England&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Strategic working note v1 | draft for discussion | August 2026&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;1. The question&lt;/h2&gt;
&lt;p&gt;England’s geology is mapped in remarkable detail. Its rivers are gauged, its aquifers designated, its groundwater bodies classified. What does not exist is a map that puts those layers together and asks a single question: where does surplus winter river flow sit beside ground that could hold it until summer?&lt;/p&gt;
&lt;p&gt;This note is a first attempt. It screens 370 river gauges across southern England for divertible winter surplus, tests each against the productive aquifers within reach, and records the regulatory state of the groundwater body beneath. It is built entirely from open data - Environment Agency flow records, BGS hydrogeology, Environment Agency groundwater bodies, Ordnance Survey rivers - and every figure in it can be re-derived.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it is not.&lt;/strong&gt; It is not a feasibility assessment and not a prediction of what would be licensed. Aquifer productivity maps say nothing about storage volume and nothing about confinement - and high productivity is as much a reason water will leave a store as a reason it will enter one. Nothing here is tested against abstraction pressure, existing licences, ecology, water quality, ground conditions or cost. It identifies where the physical ingredients coincide. That is a starting point for investigation, not a shortlist for construction.&lt;/p&gt;
&lt;h2&gt;2. Method&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Divertible resource.&lt;/strong&gt; For each gauge, from its own 2015-2025 daily mean flow record: a trigger at Q12.5 (the flow exceeded 12.5% of the time - a high flow) and a hands-off threshold at Q19, below which the river is never drawn. Divertible volume on a qualifying day is (flow - hands-off) x 86,400, annualised over water years so no winter is split across two totals. Each catchment is therefore measured against its own hydrology rather than a national threshold, and the rule is shaped like an abstraction licence condition rather than a wish.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Aquifer tiers.&lt;/strong&gt; Two, ranked, with the reasoning stated rather than buried in a score:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;tier&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;rule (BGS 1:625k, within 15 km)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;km2 in box&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;units&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 intergranular&lt;/td&gt;
&lt;td&gt;highly productive, significant intergranular flow (class 1A)&lt;/td&gt;
&lt;td&gt;1,500&lt;/td&gt;
&lt;td&gt;Lower Greensand; Triassic / Sherwood sandstone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 fractured&lt;/td&gt;
&lt;td&gt;highly productive, fracture-dominated - Chalk only (class 2A)&lt;/td&gt;
&lt;td&gt;8,681&lt;/td&gt;
&lt;td&gt;White Chalk; Grey Chalk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;excluded&lt;/td&gt;
&lt;td&gt;meets the tier-2 test, excluded by judgement&lt;/td&gt;
&lt;td&gt;747&lt;/td&gt;
&lt;td&gt;Great Oolite; Inferior Oolite&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Tier 1 ranks above tier 2 because intergranular storage behaves predictably: water occupies pore space and stays where it is put. Tier 2 is retained despite fracture flow because it is proven in practice - the North London ASR scheme stores water in confined Chalk. The Jurassic oolitic limestones meet the tier-2 classification test and are excluded by judgement, on evidence: Environment Agency borehole records show the Inferior Oolite at Mells swinging 2.37 m a year against 6.5-13.4 m in three Chalk boreholes. Thin seasonal storage, not comparable. The exclusion is drawn on the map so it can be argued with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The rule.&lt;/strong&gt; A gauge is a candidate if divertible volume exceeds 20 Mm3/yr and a tier 1 or tier 2 aquifer lies within 15 km. 73 of 370 gauges qualify.&lt;/p&gt;
&lt;h2&gt;3. Two traps, stated before the results&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Volumes are nested and must never be summed.&lt;/strong&gt; Kingston on the Thames measures the same water as Reading, Windsor and Sutton Courtenay upstream of it - and also the Mole and the Wey, which join under their own names, so grouping by river name would miss them. Systems are therefore traced through the Ordnance Survey river network. The 73 candidates collapse to 28 river systems. Adding all 73 gives 5,446 Mm3/yr; the 28 systems total 1,943. Nearly two thirds of the naive figure is the same water counted again downstream. Each row below carries its own measured volume, which already integrates everything above it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Volume is not opportunity.&lt;/strong&gt; The Thames at Kingston is the largest divertible resource in the region by a factor of two - and it appears at number 17, because ranking is by tier first. A vast flow beside fractured chalk in the most heavily abstracted reach in England is not the same prospect as a moderate flow sitting on sandstone. Sorting the table by volume alone would say the opposite, and would be wrong.&lt;/p&gt;
&lt;h2&gt;4. Results&lt;/h2&gt;
&lt;p&gt;28 river systems pass: 16 on tier 1 intergranular aquifer, 12 on Chalk. Of these, 14 sit in a groundwater body at Good quantitative status, 4 at Poor, and 10 outside any body. By river basin district the resource is more evenly spread than expected - South West 13 systems and 830 Mm3/yr, Thames 6 and 701, South East 8 and 300, Severn 1 and 112.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/assets/figures/mapping-the-opportunity/mto-1.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Figure 1. The screen. Star area is proportional to river-system divertible volume; colour is aquifer tier. Hollow circles are candidates subsumed by a system downstream and must never be added to it. Full-size version available separately.&lt;/em&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;#&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;tier&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;system&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;river&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Mm3/yr&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;subsumes&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;aquifer km&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;WFD quantitative status&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Trews Weir&lt;/td&gt;
&lt;td&gt;Exe&lt;/td&gt;
&lt;td&gt;194.8&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;11.8&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Allington&lt;/td&gt;
&lt;td&gt;Medway&lt;/td&gt;
&lt;td&gt;141.5&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Bradford on Avon&lt;/td&gt;
&lt;td&gt;Bristol Avon&lt;/td&gt;
&lt;td&gt;112.2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;12.1&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Pallingham&lt;/td&gt;
&lt;td&gt;Arun&lt;/td&gt;
&lt;td&gt;92.2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;outside any body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Crandon Bridge&lt;/td&gt;
&lt;td&gt;King’s Sedgemoor Drain&lt;/td&gt;
&lt;td&gt;81.3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4.6&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Whitford&lt;/td&gt;
&lt;td&gt;Axe&lt;/td&gt;
&lt;td&gt;70.2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;14.7&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Aller Drove Bridge&lt;/td&gt;
&lt;td&gt;Sowy River&lt;/td&gt;
&lt;td&gt;53.1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;5.2&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Taunton Market&lt;/td&gt;
&lt;td&gt;Tone&lt;/td&gt;
&lt;td&gt;39.4&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2.0&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Bason Bridge&lt;/td&gt;
&lt;td&gt;Brue&lt;/td&gt;
&lt;td&gt;38.5&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;9.3&lt;/td&gt;
&lt;td&gt;outside any body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Sherman Bridge&lt;/td&gt;
&lt;td&gt;Cuckmere&lt;/td&gt;
&lt;td&gt;38.0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0.7&lt;/td&gt;
&lt;td&gt;outside any body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Barcombe&lt;/td&gt;
&lt;td&gt;Ouse&lt;/td&gt;
&lt;td&gt;35.1&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0.6&lt;/td&gt;
&lt;td&gt;outside any body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Woodmill&lt;/td&gt;
&lt;td&gt;Culm&lt;/td&gt;
&lt;td&gt;34.8&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4.8&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Sakeham&lt;/td&gt;
&lt;td&gt;Adur&lt;/td&gt;
&lt;td&gt;33.8&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2.4&lt;/td&gt;
&lt;td&gt;outside any body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Dotton&lt;/td&gt;
&lt;td&gt;Otter&lt;/td&gt;
&lt;td&gt;31.2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Hardham&lt;/td&gt;
&lt;td&gt;Rother&lt;/td&gt;
&lt;td&gt;27.7&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;East Stoke Flume&lt;/td&gt;
&lt;td&gt;Dorset Frome&lt;/td&gt;
&lt;td&gt;25.1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;6.3&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Kingston&lt;/td&gt;
&lt;td&gt;Thames&lt;/td&gt;
&lt;td&gt;431.5&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;8.2&lt;/td&gt;
&lt;td&gt;outside any body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Throop&lt;/td&gt;
&lt;td&gt;Dorset Stour&lt;/td&gt;
&lt;td&gt;115.5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;12.1&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;East Mills Combined&lt;/td&gt;
&lt;td&gt;Hampshire Avon&lt;/td&gt;
&lt;td&gt;92.6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2.7&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Low Hall&lt;/td&gt;
&lt;td&gt;Lee&lt;/td&gt;
&lt;td&gt;41.6&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;9.4&lt;/td&gt;
&lt;td&gt;outside any body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Welford&lt;/td&gt;
&lt;td&gt;Lambourn&lt;/td&gt;
&lt;td&gt;40.6&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Pen Mill&lt;/td&gt;
&lt;td&gt;Somerset Yeo&lt;/td&gt;
&lt;td&gt;33.9&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;9.3&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Testwood&lt;/td&gt;
&lt;td&gt;Test&lt;/td&gt;
&lt;td&gt;28.0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;9.8&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Stifford&lt;/td&gt;
&lt;td&gt;Mar Dyke&lt;/td&gt;
&lt;td&gt;23.7&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0.7&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Plucks Gutter&lt;/td&gt;
&lt;td&gt;Kent Stour&lt;/td&gt;
&lt;td&gt;23.1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0.9&lt;/td&gt;
&lt;td&gt;outside any body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Redbridge&lt;/td&gt;
&lt;td&gt;Roding&lt;/td&gt;
&lt;td&gt;22.5&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;7.9&lt;/td&gt;
&lt;td&gt;outside any body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Riverside Park&lt;/td&gt;
&lt;td&gt;Itchen&lt;/td&gt;
&lt;td&gt;21.7&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;7.6&lt;/td&gt;
&lt;td&gt;outside any body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Chiselborough&lt;/td&gt;
&lt;td&gt;Parrett&lt;/td&gt;
&lt;td&gt;20.1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;7.2&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Shaded rows are the Somerset Levels cluster (section 5). ‘Aquifer km’ is the distance to the aquifer of the row’s own tier. ‘Subsumes’ counts upstream candidates whose water this row already contains.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;5. The finding that was not expected&lt;/h2&gt;
&lt;p&gt;The Somerset Levels - the landscape that motivated this work because of its flooding, not its geology - return the largest single cluster in the region. Seven systems in the table lie in or immediately around the Levels: King’s Sedgemoor Drain at Crandon Bridge (81.3 Mm3/yr), the Axe at Whitford (70.2), the Sowy at Aller Drove Bridge (53.1), the Tone at Taunton Market (39.4), the Brue at Bason Bridge (38.5), the Somerset Yeo at Pen Mill (33.9) and the Parrett at Chiselborough (20.1). Together they represent 336 Mm3/yr of divertible winter surplus - more than any other locality in the screen, and drawn from a landscape whose water problem is conventionally described as an excess.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Five of the seven are tier 1,&lt;/strong&gt; on Triassic sandstone with significant intergranular flow, at measured distances of 2.0 to 9.3 km - not the 42 km to the Dorset Chalk that earlier work in this programme had assumed was the nearest credible store. Four sit in the ‘Tone and North Somerset Streams’ groundwater body at Good quantitative status. This is a regional screen that knew nothing about the Somerset project, applying a uniform rule to 370 gauges, and it nominated the Levels independently.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The caution that must travel with it.&lt;/strong&gt; The Triassic outcrops are small (242 km2 across the whole region), the screen measures distance to outcrop rather than the presence of a usable store, and the BGS summary for these rocks notes they become saline at depth beneath confining Mercia Mudstone - which is simultaneously the confinement that would make storage work and a water-quality limit on where it could. Nothing here establishes that a store exists. It establishes where to look, and that the answer may be much closer to hand than assumed.&lt;/p&gt;
&lt;h2&gt;6. What this screen cannot see&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Confinement - the decisive property.&lt;/strong&gt; Whether an aquifer holds a winter’s water or drains it in weeks is set by confinement, not by productivity class. Local measurement in this programme put unconfined Chalk recession at a 41-day half-life. The Water Framework Directive dataset carries no confinement attribute at all: across all 123 groundwater bodies in the study area, the relevant fields are uniformly ‘Not Applicable’. Distance to a mapped covering formation is reported as a proxy, but the 1:625k map shows bedrock at outcrop - where Chalk is confined beneath London Clay the map shows London Clay - so the proxy locates the edge of a confined margin and cannot demonstrate confinement at a point. Confinement must come from borehole logs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage volume.&lt;/strong&gt; No open dataset supplies it. The BGS aquifer-properties service was queried directly during this work: it is a site index recording where property data is held, with no transmissivity and no storativity values. Productivity class describes how readily water moves, not how much the rock will hold.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Licensing and abstraction pressure.&lt;/strong&gt; The WFD quantitative status column is reported and deliberately not scored, because it cuts both ways: Poor status is where recharge is most wanted and new abstraction hardest to permit; Good status beside a protected chalk stream may be untouchable. Existing licences are not modelled.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source protection zones.&lt;/strong&gt; No SPZ dataset was available; the join is written and the column will populate when one is supplied.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost, terrain and conveyance.&lt;/strong&gt; No pipeline routing, no pumping head, no capital cost. Two candidates with equal volume and equal distance may differ by an order of magnitude in cost once lift and route are considered.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7. What follows&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Read the map as a shortlist for desk study, not for schemes.&lt;/strong&gt; The right next step at any candidate is borehole logs: does a usable thickness of aquifer exist, is it confined, and what do its records say about yield?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Investigate the Somerset Triassic first.&lt;/strong&gt; It is the largest cluster, the aquifer is intergranular and close, and the local modelling programme already has the flow records, terrain and demand context to test a scheme there quickly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add the missing layers.&lt;/strong&gt; Source protection zones, abstraction licences and returns, and protected-site boundaries would each move candidates around, and all three are open data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Treat the two tiers as different products.&lt;/strong&gt; Local modelling in this programme suggests intergranular and fractured settings do different jobs: a confined store banks water for summer supply, while a fast-draining one returns it to the river as delayed baseflow. Both are useful; they are not interchangeable, and a candidate should be judged against the product it can actually deliver.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;England has mapped its geology in remarkable detail. The next task is to map the strategic opportunity that geology presents - and then to test, at a handful of places, whether the opportunity is real.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Sources and attribution: flow data from the Environment Agency Hydrology API, daily mean 2015-2025 (OGL v3). Geology: BGS 1:625k Hydrogeology © UKRI. Groundwater bodies and river basin districts © Environment Agency, OGL v3. Contains OS data © Crown copyright and database right 2026. Method, full 28-system table with all attributes, and the appendix of subsumed gauges are in the accompanying technical report.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This note was written in Word; the text above is a faithful conversion, and the original is the authoritative copy.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/assets/docs/mapping_the_opportunity_v1.docx&quot;&gt;Download the original (.docx)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Read the method note behind it: &lt;a href=&quot;/notes/mapping-the-opportunity-method/&quot;&gt;Mapping the opportunity — how it was built&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>The Jacobian Conjecture</title>
    <link href="https://themetalevel.org/notes/jacobian-conjecture/"/>
    <updated>2026-08-09T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/jacobian-conjecture/</id>
    <summary>A walk down to the determinant and back up again — one main paper, and the notes that came out of writing it.</summary>
    <content type="html">&lt;a class=&quot;hero-link&quot; href=&quot;/notes/one-formula-many-worlds/&quot;&gt;
&lt;img src=&quot;/assets/figures/jacobian-conjecture/NeedleEntry.png&quot; alt=&quot;Looking down the needle: the fiber of the counterexample as one geometric object&quot;&gt;
&lt;span class=&quot;hero-link-body&quot;&gt;
&lt;span class=&quot;hero-link-kicker&quot;&gt;The main paper&lt;/span&gt;
&lt;strong class=&quot;hero-link-title&quot;&gt;One Formula, Many Worlds&lt;/strong&gt;
&lt;span class=&quot;hero-link-note&quot;&gt;A walk down to the determinant and back up to the broken Jacobian conjecture. Thirteen sections, twenty-two figures, and one ladder with no missing rungs.&lt;/span&gt;
&lt;/span&gt;
&lt;/a&gt;
&lt;p&gt;The conjecture fell in 2026. This is the expedition that went down after
it: what the determinant is actually measuring, why the schoolroom
prohibition on dividing by zero is the same rule as Jacobi’s dependence
alarm, and what the counterexample looks like when you stand close
enough to see its shape.&lt;/p&gt;
&lt;p&gt;The main paper is the spine. Everything below came out of writing it —
a field appendix that examines the counterexample’s fiber as a single
geometric object, a research note seeking expert assessment, and a
one-page seed for where the ladder goes next.&lt;/p&gt;
&lt;h2&gt;The papers&lt;/h2&gt;
&lt;div class=&quot;panels panels--row&quot;&gt;
&lt;article class=&quot;card&quot;&gt;&lt;a href=&quot;/notes/bracket-and-unique-mechanism/&quot;&gt;&lt;span class=&quot;card-art&quot;&gt;&lt;img src=&quot;/assets/figures/bracket-and-unique-mechanism/fig-01.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/span&gt;&lt;span class=&quot;card-body&quot;&gt;&lt;span class=&quot;entry-meta&quot;&gt;&lt;span&gt;Research note&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;card-title&quot;&gt;Bracket and Unique Mechanism&lt;/span&gt;&lt;span class=&quot;card-note&quot;&gt;A research note from the Determinant Ladder expedition — observation and programme, seeking expert assessment.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/article&gt;
&lt;article class=&quot;card&quot;&gt;&lt;a href=&quot;/notes/down-the-needle/&quot;&gt;&lt;span class=&quot;card-art&quot;&gt;&lt;img src=&quot;/assets/figures/down-the-needle/fig-01.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/span&gt;&lt;span class=&quot;card-body&quot;&gt;&lt;span class=&quot;entry-meta&quot;&gt;&lt;span&gt;Field appendix&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;card-title&quot;&gt;Down the Needle&lt;/span&gt;&lt;span class=&quot;card-note&quot;&gt;A field appendix to One Formula, Many Worlds: the fiber of the counterexample as one geometric object · August 2026 · third edition&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/article&gt;
&lt;article class=&quot;card&quot;&gt;&lt;a href=&quot;/notes/where-the-ladder-goes/&quot;&gt;&lt;span class=&quot;card-art card-art--generated&quot; style=&quot;--art: #8a5a3d&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;card-art-label&quot;&gt;Paper II seed&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;card-body&quot;&gt;&lt;span class=&quot;entry-meta&quot;&gt;&lt;span&gt;Paper II seed&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;card-title&quot;&gt;Where The Ladder Goes&lt;/span&gt;&lt;span class=&quot;card-note&quot;&gt;A one-page seed for Paper II of the Determinant Ladder expedition.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/article&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Why this exists</title>
    <link href="https://themetalevel.org/notes/why-this-exists/"/>
    <updated>2026-08-09T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/why-this-exists/</id>
    <summary>A place to put work down where it can be found again — including the half-finished parts.</summary>
    <content type="html">&lt;p&gt;Most of what I do ends up as a folder. A model, some figures, a document
that explains itself to nobody but me, and then the next thing starts.
This site is the attempt to stop that.&lt;/p&gt;
&lt;p&gt;The rule I am setting myself is that a piece goes up when it is
&lt;em&gt;legible&lt;/em&gt;, not when it is finished. A study with an open question at the
end is more useful than one that quietly drops the question. So expect
loose ends.&lt;/p&gt;
&lt;p&gt;Things are filed under a &lt;a href=&quot;/projects/&quot;&gt;project&lt;/a&gt; when one fits, and left
unfiled when none does. The filing is deliberately cheap to change —
work migrates between projects, projects merge, projects get abandoned,
and none of that should cost anything or break a link.&lt;/p&gt;
&lt;p&gt;If something here is wrong, I would like to know.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The Overspill</title>
    <link href="https://themetalevel.org/notes/the-overspill/"/>
    <updated>2026-08-01T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/the-overspill/</id>
    <summary>Fill-to-ten is grouping on instruction. Overspill is grouping because the container ran out.</summary>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Owns:&lt;/strong&gt; The overspill mode — how the addends are laid, how the carry becomes visible as a &lt;em&gt;consequence&lt;/em&gt;, and why the representation fades by number type without any adaptive logic.
&lt;strong&gt;Supersedes:&lt;/strong&gt; nothing. Addendum to &lt;code&gt;Exchange.md&lt;/code&gt;, which owns the exchange act itself and rulings E1–E8.
&lt;strong&gt;Status:&lt;/strong&gt; Committed as built. &lt;code&gt;CalculationRoom1D&lt;/code&gt; (Counting) ships on this spec and has been playtested.
&lt;strong&gt;Cited by:&lt;/strong&gt; &lt;code&gt;calculation_room_1d.gd:12&lt;/code&gt; · &lt;code&gt;exchange_rod.gd:83, 110, 483&lt;/code&gt; · &lt;code&gt;The_Pass_Ledger:212&lt;/code&gt;.
&lt;strong&gt;Note:&lt;/strong&gt; §5 stage 1 is built; stages 2–4 are designed and unbuilt. §8 records what was in scope for the Counting build.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h1&gt;The Overspill&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Fill-to-ten is grouping on instruction. Overspill is grouping because the container ran out.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1 · The act&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;7 + 6&lt;/code&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The child places &lt;strong&gt;7&lt;/strong&gt; in the ledger → &lt;strong&gt;seven units appear in the rod below&lt;/strong&gt;, laid along it&lt;/li&gt;
&lt;li&gt;The child places &lt;strong&gt;&lt;code&gt;+&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;6&lt;/strong&gt; (either order — but the operator must be placed)&lt;/li&gt;
&lt;li&gt;The six are laid on &lt;strong&gt;after&lt;/strong&gt; the seven → &lt;strong&gt;the frame overspills&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;The excess &lt;strong&gt;3 pulsate&lt;/strong&gt; — held, marked, watchable&lt;/li&gt;
&lt;li&gt;They &lt;strong&gt;lift into a second row&lt;/strong&gt;, on top of the first&lt;/li&gt;
&lt;li&gt;Count &lt;strong&gt;full rows&lt;/strong&gt; → 1 → tens column&lt;/li&gt;
&lt;li&gt;Count the &lt;strong&gt;loose row&lt;/strong&gt; → 3 → units column&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Ledger and rod are synchronised.&lt;/strong&gt; Placing a digit in the notation makes the quantity appear beneath it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;★ That synchronisation &lt;em&gt;is&lt;/em&gt; A1’s bridge, running live: &lt;strong&gt;the rod holds the quantity, the ledger records it&lt;/strong&gt;, and the child watches the two agree. The violation in &lt;code&gt;place_value_house&lt;/code&gt; is a chart being asked to hold both. Here they are two objects moving together.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;2 · Why the overspill is better&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;The child sees&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fill-to-ten&lt;/td&gt;
&lt;td&gt;&lt;em&gt;“when you reach ten, group them”&lt;/em&gt; — a &lt;strong&gt;rule&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Overspill&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the frame is full and &lt;strong&gt;there is more&lt;/strong&gt; — the excess &lt;em&gt;has nowhere to be&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The regrouping stops being an instruction and becomes a &lt;strong&gt;consequence of the material running out of room&lt;/strong&gt;. That is a gift of the mechanic in the frozen sense: the honest physics does the teaching, and no dialogue is required.&lt;/p&gt;
&lt;p&gt;The pulsate is the beat that makes it work — the excess is marked and held long enough for the child to predict what must happen before it happens.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3 · The array reading — and how it must NOT look&lt;/h2&gt;
&lt;p&gt;Two rows, first full, second holding three. &lt;strong&gt;Count the full rows; count the leftover.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;★ &lt;strong&gt;Place value is the array with its width locked to the base.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which is why &lt;code&gt;10 × 10&lt;/code&gt; is the hundred square, and why one component gives rod, array and hundred by changing &lt;code&gt;capacity&lt;/code&gt; and &lt;code&gt;columns&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;⚠ This is not the times-table array, and the visual must say so&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Cells are&lt;/th&gt;
&lt;th&gt;Stay individuated?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Times-table array&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;countable units &lt;strong&gt;of the product&lt;/strong&gt; — both dimensions meaningful&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;yes, throughout&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Carry array&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;containers of the base — only the &lt;em&gt;count of full rows&lt;/em&gt; matters&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;no — a full row stops being ten cells&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A sealed row &lt;strong&gt;is one ten&lt;/strong&gt;. If it still reads as ten cells, the material is asserting the opposite of what sealing means. §6 is how the visual carries that.&lt;/p&gt;
&lt;p&gt;The rhyme with multiplication is a special case, not an identity — worth using, not over-claiming. A child doing column addition still meets array structure before Venus, which is transfer arriving in the material rather than the curriculum.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;4 · It is the bar, not the number line&lt;/h2&gt;
&lt;p&gt;The apparatus below the ledger lays quantities &lt;strong&gt;end to end as lengths&lt;/strong&gt;. That is the &lt;strong&gt;bar&lt;/strong&gt; — cardinal, quantity-as-length (T3). The number line is &lt;strong&gt;positions&lt;/strong&gt; — start at 7, hop 6, land on 13 (T4). A3 keeps them apart.&lt;/p&gt;
&lt;p&gt;Visually near-identical; conceptually different; &lt;strong&gt;and showing both is standard, valuable practice&lt;/strong&gt; — the bar answers &lt;em&gt;how much&lt;/em&gt;, the line answers &lt;em&gt;where you land&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So the rhyme is a feature, provided the corridor knows which is which:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The line gives the operation its meaning. The bar gives the carry its structure.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;One consequence for the build:&lt;/strong&gt; the two addends should be &lt;strong&gt;visually distinct&lt;/strong&gt; in the rod — 7 in one shade, 6 in another. Then 13 reads two ways at once: as &lt;em&gt;seven-and-six&lt;/em&gt; (the bond) and as &lt;em&gt;one-ten-and-three&lt;/em&gt; (the place value). The double reading is the whole point, and it continues &lt;code&gt;shrine_of_bonds&lt;/code&gt;’ work rather than repeating it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;5 · The fade — free, because the numbers grow&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Representation&lt;/th&gt;
&lt;th&gt;Works to&lt;/th&gt;
&lt;th&gt;Arrives at&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Lay along, overspill&lt;/strong&gt; — the addends as extents&lt;/td&gt;
&lt;td&gt;~20, max 30&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Counting&lt;/strong&gt; (max 9+9 = 18)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Pour and fill rows&lt;/strong&gt; — no linear lay-out first&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Whole&lt;/strong&gt; (bigger sums)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Flats&lt;/strong&gt; — a hundred is one object&lt;/td&gt;
&lt;td&gt;beyond&lt;/td&gt;
&lt;td&gt;hundreds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ledger only&lt;/strong&gt; — carry mark, no material&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;fluency&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;No adaptive logic and no flags.&lt;/strong&gt; Counting’s bounds keep sums inside the line’s readable range; Whole’s bounds push past it; hundreds push past that. &lt;strong&gt;The material’s limits and the number-type bounds coincide&lt;/strong&gt; — which is usually a sign the structure is right rather than imposed.&lt;/p&gt;
&lt;p&gt;Stage 1 shows &lt;em&gt;why&lt;/em&gt; the row breaks. Stage 2 assumes you know, and just does it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;6 · ★ The seal is a visual unification that keeps the parts&lt;/h2&gt;
&lt;p&gt;The two addends are &lt;strong&gt;different colours&lt;/strong&gt; — 7 in one, 6 in another. On seal, the full row is &lt;strong&gt;shaded over&lt;/strong&gt;: a darker treatment in the same hue family, so the two colours remain legible underneath.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Both readings survive at once:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;seven-and-six&lt;/em&gt; — the bond, still visible through the shading&lt;/li&gt;
&lt;li&gt;&lt;em&gt;one-ten-and-three&lt;/em&gt; — the place value, asserted by the unification&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Shading rather than recolouring is what keeps the first reading. Recolouring to a single ten-colour would erase the bond and repeat what &lt;code&gt;shrine_of_bonds&lt;/code&gt; already taught rather than continuing it.&lt;/p&gt;
&lt;h3&gt;And the cell structure goes&lt;/h3&gt;
&lt;p&gt;On seal, the row’s internal dividers &lt;strong&gt;fade&lt;/strong&gt;, and the row reads as &lt;strong&gt;one bar&lt;/strong&gt; rather than ten boxes.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Reads as&lt;/th&gt;
&lt;th&gt;Because&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Loose row&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;individuated cells&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;these are still separate countable units&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sealed row&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;one shaded bar&lt;/strong&gt;, two colour regions&lt;/td&gt;
&lt;td&gt;this is now &lt;strong&gt;one ten&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;★ &lt;strong&gt;Sealing turns ten discrete things into one continuous thing.&lt;/strong&gt; That is precisely what promotion to the next denomination &lt;em&gt;means&lt;/em&gt; — and it makes the sealed row into a &lt;strong&gt;bar&lt;/strong&gt;, which is what a ten is at the next level up.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It also settles §3 without a rule: the times-table array keeps its cells because every cell is a countable unit of the product; the carry array loses them on seal because the row has stopped being ten of anything.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;7 · Who does what&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Act&lt;/th&gt;
&lt;th&gt;Whose&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Placing digits and &lt;code&gt;+&lt;/code&gt; in the ledger&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;child&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the operator is a pre-emption; it cannot be omitted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Units appearing in the rod&lt;/td&gt;
&lt;td&gt;automatic&lt;/td&gt;
&lt;td&gt;notation and quantity are synchronised&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overspill and lift to row 2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;automatic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;it is physics, not a choice — the excess has nowhere else to be&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Counting rows and leftover&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;child&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the interpretation, which is where the mathematics is&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Writing the carry and the units digit&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;child&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;notation is the child’s understanding, not the material’s behaviour&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The rule:&lt;/strong&gt; &lt;em&gt;the material behaves; the notation is authored.&lt;/em&gt; The excess must lift — there is nowhere else for it — but nothing is written down until the child writes it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;8 · Tonight&lt;/h2&gt;
&lt;p&gt;Counting is single digit + single digit, so &lt;strong&gt;stage 1 only&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Needed:&lt;/strong&gt; one frame, two addends laid distinctly, overspill, pulsate, lift to row 2, child counts and records.
&lt;strong&gt;Not needed:&lt;/strong&gt; pour-fill mode · flats · a tens frame that fills · regroup-down (single-digit subtraction never regroups — that arrives with Whole).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;3 + 5&lt;/code&gt; must produce &lt;strong&gt;eight loose in one row, no overspill, no carry&lt;/strong&gt; — the no-carry case has to look plainly different from the carry case, or the carry teaches nothing.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Institution hierarchy, class instances and student allocation</title>
    <link href="https://themetalevel.org/notes/lfti-institution-hierarchy/"/>
    <updated>2026-05-23T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/lfti-institution-hierarchy/</id>
    <summary>This is a substantial structural prompt. Read the full codebase before starting — particularly the existing node structure, auth system, project wizard, tool instance view, and…</summary>
    <content type="html">&lt;p&gt;This is a substantial structural prompt. Read the full codebase before starting —
particularly the existing node structure, auth system, project wizard, tool instance
view, and group instance nodes. Understand what exists before changing anything.&lt;/p&gt;
&lt;p&gt;Build and verify each phase before starting the next. Do not proceed to Phase B
until Phase A is confirmed working.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;OVERVIEW&lt;/h2&gt;
&lt;p&gt;This prompt does four things in sequence:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phase A&lt;/strong&gt; — Restructure institution hierarchy (Root → Country → Institution)
and fix person node placement&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase B&lt;/strong&gt; — Class instance node type and class assignment&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase C&lt;/strong&gt; — Live student allocation with role-based group limits and
teacher override&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase D&lt;/strong&gt; — Cross-class view at tool instance level and feedforward to Collate&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;PHASE A — Institution Hierarchy &amp;amp; Person Node Placement&lt;/h2&gt;
&lt;h3&gt;Target structure&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;LFTI (root)
  ├── Reference Instance
  └── Country (UK)
        └── Institution (Bristol Academy)
              ├── Staff
              │     ├── Institution Admin
              │     ├── Teacher
              │     └── [assigned facilitators via involves relation]
              ├── Students
              │     └── Class (11S1)
              │           ├── Tom P (person node)
              │           └── Sarah K (person node)
              └── Projects
                    └── LFTI 2026
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Database migration&lt;/h3&gt;
&lt;p&gt;The existing &lt;code&gt;uk&lt;/code&gt; and &lt;code&gt;zm&lt;/code&gt; nodes are country groupings, not institutions.
Specific institution nodes need to sit under them.&lt;/p&gt;
&lt;p&gt;Run a migration in &lt;code&gt;db/database.js&lt;/code&gt; on startup (check if already run via a
migrations table):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE TABLE IF NOT EXISTS migrations (
  id TEXT PRIMARY KEY,
  run_at TEXT NOT NULL
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Migration: inst_hierarchy_v1&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create &lt;code&gt;Staff&lt;/code&gt; and &lt;code&gt;Students&lt;/code&gt; container nodes under each existing institution node
(uk, zm, inst_lfti). These are simple nodes with type: &lt;code&gt;container&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Move existing person nodes: reparent them under the correct institution’s Staff
or Students container. Match by institution_id in their meta.&lt;/li&gt;
&lt;li&gt;Dev seed users: reparent to inst_lfti Staff container.&lt;/li&gt;
&lt;li&gt;UK-institution person nodes (UK School Admin, Mr J Clark): reparent to uk Staff
container for now (will move to specific school when school nodes are created).&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;parent_id&lt;/code&gt; correctly on all person nodes — never null for a person node.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Migration: project_container_v1&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Under each institution node, create a &lt;code&gt;Projects&lt;/code&gt; container node (type: container).&lt;/li&gt;
&lt;li&gt;Reparent existing project nodes to sit under their institution’s Projects container.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;New node types&lt;/h3&gt;
&lt;p&gt;Add to the recognised type list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;country&lt;/code&gt; — top-level geographic grouping (UK, NZ, Zambia)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;container&lt;/code&gt; — organisational wrapper (Staff, Students, Projects, Classes)
Containers have no content of their own — they exist to organise children.
In the tree, containers render without a type badge, just their title.
In the content section, containers show only their children grid, no body editor.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Creating a new institution (system admin only)&lt;/h3&gt;
&lt;p&gt;System admin creates a Country node first (if it doesn’t exist), then an
Institution node under it. On Institution node creation, automatically generate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Staff container node&lt;/li&gt;
&lt;li&gt;Students container node&lt;/li&gt;
&lt;li&gt;Projects container node&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This should happen via a dedicated endpoint:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /api/institutions
  body: { name, country_id, admin_name, admin_email }
  Auth: superadmin only
  Creates: institution node + 3 container nodes + institution admin person node
           under Staff container
  Returns: { institution_id, admin_person_id }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The institution admin person node is created with &lt;code&gt;meta.invite_status: &amp;quot;pending&amp;quot;&lt;/code&gt;.
Print their credentials to the server console (same pattern as dev seed).&lt;/p&gt;
&lt;h3&gt;Institution admin scoping&lt;/h3&gt;
&lt;p&gt;Institution admins can only create projects under their institution’s Projects
container. Enforce this in &lt;code&gt;POST /api/projects&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If role is institution_admin, verify that the target parent node is the Projects
container of their institution. Reject with 403 if not.&lt;/li&gt;
&lt;li&gt;Superadmin can create projects anywhere.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Project wizard changes&lt;/h3&gt;
&lt;p&gt;In the project wizard Step 1, the institution field is now read-only for
institution_admin role — pre-filled with their institution. Only superadmin
sees a dropdown to choose any institution.&lt;/p&gt;
&lt;h3&gt;Facilitator assignment&lt;/h3&gt;
&lt;p&gt;Facilitators are person nodes that may exist at country or root level (they
work across multiple institutions). They are assigned to an institution or
project via an &lt;code&gt;involves&lt;/code&gt; relation — not moved in the tree.&lt;/p&gt;
&lt;p&gt;In the Participants tab of the project dashboard, when adding a facilitator:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Search first among person nodes that have &lt;code&gt;involves&lt;/code&gt; relations to this
institution or its country ancestor&lt;/li&gt;
&lt;li&gt;Also search all person nodes with role: facilitator system-wide&lt;/li&gt;
&lt;li&gt;Selecting one adds an &lt;code&gt;involves&lt;/code&gt; relation from the facilitator’s person node
to the project node — does not change parent_id&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verify Phase A&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;As superadmin, create a new institution “Bristol Academy” under UK.
Staff, Students, Projects containers auto-generate.
Institution admin person node created under Staff. Credentials printed to console.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Log in as the new institution admin. Project wizard Step 1 shows Bristol Academy
pre-filled, not editable. Creating a project places it under Bristol Academy →
Projects container.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Attempting to create a project under UK Schools (wrong institution) as
institution_admin returns 403.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All existing person nodes are now under institution Staff or Students containers,
not at root level.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;PHASE B — Class Instance Node &amp;amp; Class Assignment&lt;/h2&gt;
&lt;h3&gt;Class instance node&lt;/h3&gt;
&lt;p&gt;A class instance is a thin wrapper that represents a specific class doing a
specific tool instance. It sits between the tool instance and the group instances.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Tool Instance (Transect Walk)
  ├── Class Instance (11S1 — Transect Walk)   ← new node type
  │     ├── Group 1
  │     │     └── Contributions
  │     └── Group 2
  └── Class Instance (9J1 — Transect Walk)
        └── Groups...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Class instance node structure:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;id&amp;quot;: &amp;quot;ci_[timestamp]_[random]&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;class_instance&amp;quot;,
  &amp;quot;title&amp;quot;: &amp;quot;[Class name] — [Tool name]&amp;quot;,
  &amp;quot;parent_id&amp;quot;: &amp;quot;[tool_instance_id]&amp;quot;,
  &amp;quot;relations&amp;quot;: [
    { &amp;quot;type&amp;quot;: &amp;quot;involves&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;[class_node_id]&amp;quot; },
    { &amp;quot;type&amp;quot;: &amp;quot;contains&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;[group_instance_id]&amp;quot; }
  ],
  &amp;quot;meta&amp;quot;: {
    &amp;quot;tool_instance_id&amp;quot;: &amp;quot;[tool_instance_id]&amp;quot;,
    &amp;quot;class_node_id&amp;quot;: &amp;quot;[class_node_id]&amp;quot;,
    &amp;quot;class_name&amp;quot;: &amp;quot;[class name for display]&amp;quot;,
    &amp;quot;status&amp;quot;: &amp;quot;not_started&amp;quot;,
    &amp;quot;allocation_locked&amp;quot;: false,
    &amp;quot;approval_status&amp;quot;: &amp;quot;pending&amp;quot;,
    &amp;quot;teacher_node_id&amp;quot;: null,
    &amp;quot;num_groups&amp;quot;: 3
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Status values:&lt;/strong&gt; not_started → active → submitted → approved&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Group instances&lt;/strong&gt; are now children of class_instance nodes, not tool_instance
nodes directly. Update &lt;code&gt;POST /api/tool-instances&lt;/code&gt; and the regenerate-groups
endpoint accordingly.&lt;/p&gt;
&lt;h3&gt;Class assignment at project level&lt;/h3&gt;
&lt;p&gt;In the project wizard Step 3 (Participants), add a Classes section:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CLASSES ASSIGNED TO THIS PROJECT
[ + Assign class ]

11S1  ·  Mr J Clark  ·  ~30 students   [×]
9J1   ·  Ms Ahmed    ·  ~25 students   [×]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;“+ Assign class” searches class nodes under this institution’s Students container.
Selecting a class stores it in &lt;code&gt;project.meta.assigned_classes: [&amp;quot;class_node_id&amp;quot;]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When the project is created, class assignment does NOT automatically create
class_instance nodes under every tool instance — that happens at the tool
instance level. Project-level assignment is just a pre-selection for convenience.&lt;/p&gt;
&lt;h3&gt;Class assignment at tool instance level&lt;/h3&gt;
&lt;p&gt;In the tool instance Setup tab, add a Class Assignment section above Group Configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CLASSES DOING THIS TOOL

[ + Add class ]  (searches institution&#39;s classes, pre-selects project&#39;s assigned classes)

┌─────────────────────────────────────┐
│ 11S1  ·  Mr J Clark  ·  30 students │
│ Groups: 6  [configure →]  [×]       │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 9J1   ·  Ms Ahmed  ·  25 students   │
│ Groups: 5  [configure →]  [×]       │
└─────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adding a class here creates a class_instance node as a child of the tool instance,
with group_instance children based on num_groups for that class.&lt;/p&gt;
&lt;p&gt;Removing a class (×) deletes the class_instance node and all its group_instance
children. Confirm first: “This will remove all groups and contributions for 11S1
from this tool instance. Are you sure?”&lt;/p&gt;
&lt;p&gt;“Configure →” opens the group configuration for that class (replaces the current
single-class group configuration in Setup tab).&lt;/p&gt;
&lt;h3&gt;Approval at class instance level&lt;/h3&gt;
&lt;p&gt;The class instance has its own approval state. The flow is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Group contribution (pending)
  → approved by teacher/facilitator at class instance level
  → class instance status: submitted (all groups have ≥1 approved contribution)
  → approved by facilitator at tool instance level (cross-class review)
  → feeds into phase-level Collate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the tool instance Contributions tab, add a class filter above the group filter:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ All classes ] [ 11S1 ] [ 9J1 ]
[ All groups  ] [ Group 1 ] [ Group 2 ] ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Class-level approval: a “Mark class as submitted” button appears in the class
instance view when all groups in that class have ≥1 approved contribution.
Sets class_instance.meta.status = “submitted”.&lt;/p&gt;
&lt;h3&gt;Verify Phase B&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In project wizard, assign 11S1 and 9J1 to the project.
project.meta.assigned_classes contains both class node ids.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In a tool instance Setup tab, both classes appear pre-selected.
Adding a class creates a class_instance node under the tool instance.
Each class_instance has group_instance children.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the tool instance Contributions tab, class filter tabs appear.
Filtering by 11S1 shows only 11S1’s contributions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Removing a class from the tool instance (after confirmation) removes
the class_instance and all its group_instance children from the tree.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;PHASE C — Live Student Allocation&lt;/h2&gt;
&lt;h3&gt;The allocation model&lt;/h3&gt;
&lt;p&gt;Students self-assign to groups using a group token on their device.
Teachers can override any assignment. Teacher can lock allocation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Authority hierarchy:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Student token → can self-assign if space available (role slots not full)
Teacher/facilitator → can assign/unassign any student, overrides student choice
Lock (teacher sets on class_instance) → freezes student self-assignment;
     only teacher can move students after lock
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Role-based group size limit:&lt;/strong&gt;
Group capacity = number of roles defined on the tool instance’s steps meta.
If a tool instance has roles: [Navigator, Sketcher, Note-taker, Interviewer],
group capacity is 4. A student trying to join a full group sees:
“This group is full (4/4 roles filled).”
If no roles are defined, default capacity is the num_groups divisor
(class size ÷ num_groups, rounded up).&lt;/p&gt;
&lt;h3&gt;Group token system&lt;/h3&gt;
&lt;p&gt;Each group_instance gets a short unique token on creation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function generateGroupToken() {
  const chars = &#39;ABCDEFGHJKLMNPQRSTUVWXYZ23456789&#39;; // no ambiguous chars
  return Array.from({length: 6}, () =&amp;gt;
    chars[Math.floor(Math.random() * chars.length)]
  ).join(&#39;&#39;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Token stored in &lt;code&gt;group_instance.meta.token&lt;/code&gt;.
Tokens are unique within a tool instance (check on generation).&lt;/p&gt;
&lt;h3&gt;Token login endpoint&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;POST /api/token-login
  body: { token }
  No auth required — this is the student entry point
  Finds the group_instance with matching meta.token
  Returns: {
    group_instance_id,
    group_name,
    class_instance_id,
    class_name,
    tool_instance_id,
    tool_name,
    institution_name,
    session_token   ← a short-lived session (24hr) with role: &amp;quot;group_token&amp;quot;
  }
  Sets cookie: lfti_group_session=&amp;lt;session_token&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add &lt;code&gt;group_token&lt;/code&gt; as a new role to the auth system.
Group token sessions are stored in the sessions table with
&lt;code&gt;meta.group_instance_id&lt;/code&gt; and &lt;code&gt;meta.class_instance_id&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A group_token session can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;View their class instance’s unallocated student list&lt;/li&gt;
&lt;li&gt;Self-assign to their group (if space and not locked)&lt;/li&gt;
&lt;li&gt;Add contributions to their group_instance (when allocation is complete)&lt;/li&gt;
&lt;li&gt;View their group’s contributions and approval status&lt;/li&gt;
&lt;li&gt;View class-example contributions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A group_token session cannot:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;See other groups’ contributions&lt;/li&gt;
&lt;li&gt;Access any other project, institution, or node&lt;/li&gt;
&lt;li&gt;Approve contributions&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Unallocated student list&lt;/h3&gt;
&lt;p&gt;The class instance carries the authoritative allocation state:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;meta&amp;quot;: {
  ...
  &amp;quot;allocation&amp;quot;: {
    &amp;quot;unallocated&amp;quot;: [&amp;quot;Tom P&amp;quot;, &amp;quot;Sarah K&amp;quot;, &amp;quot;Amara D&amp;quot;, ...],
    &amp;quot;locked&amp;quot;: false
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a class is assigned to a tool instance (Phase B), the unallocated list
is populated from the class node’s student person nodes (first name + last initial).
If no student roster exists for the class yet, unallocated list starts empty
and students can add their name when joining via token.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unallocated list API:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET /api/class-instances/:id/allocation
  Returns: { unallocated: [...], groups: [{id, name, members, capacity}], locked: bool }
  Auth: any session with access to this class_instance (group_token, facilitator+)
  Polls every 10 seconds on the token login view

POST /api/class-instances/:id/assign
  body: { student_name, group_instance_id }
  Auth: group_token (can only assign to their own group if not locked)
        facilitator+ (can assign to any group)
  Validates: group not at capacity, not locked (unless facilitator+)
  Moves student_name from unallocated to group_instance.meta.members
  Returns: updated allocation state

POST /api/class-instances/:id/unassign
  body: { student_name, group_instance_id }
  Auth: group_token (can unassign from their own group if not locked)
        facilitator+ (can unassign from any group, ignores lock)
  Returns: updated allocation state

POST /api/class-instances/:id/lock
  body: { locked: true|false }
  Auth: facilitator+ only
  Sets class_instance.meta.allocation.locked
  Returns: { locked: bool }
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Token login UI&lt;/h3&gt;
&lt;p&gt;A separate minimal page at &lt;code&gt;/join&lt;/code&gt; — no main app chrome, no tree, no nav.
URL: &lt;code&gt;http://localhost:3000/join&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────┐
│              LFTI                        │
│                                         │
│  Enter your group code                  │
│                                         │
│  [ X K 7 2 A 3           ]             │
│                                         │
│  [ Join →                ]             │
│                                         │
│  Ask your teacher for the code          │
│  printed on your group&#39;s worksheet.     │
│                                         │
└─────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On successful token entry, show the group allocation view:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────┐
│ LFTI · Bristol Academy                  │
│ Transect Walk · 11S1 · Group 2          │
├─────────────────────────────────────────┤
│ WHO&#39;S IN YOUR GROUP?                    │
│                                         │
│ Tap your name to join this group.       │
│ Not on the list? Type your name below.  │
│                                         │
│ UNALLOCATED (tap to join):              │
│ [ Tom P ] [ Sarah K ] [ Amara D ]      │
│ [ James W ] [ Priya N ] [ ...  ]       │
│                                         │
│ YOUR GROUP (Group 2):                   │
│ ✓ Marcus T  — Navigator                │
│ ✓ Yemi O    — Sketcher                 │
│ ○ [empty]   — Note-taker              │
│ ○ [empty]   — Interviewer             │
│                                         │
│ [2/4 members joined]  [Not locked]      │
│                                         │
│ [ I&#39;m done — start the activity ]       │
│ (appears when ≥1 member in this group)  │
└─────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tapping a name in the unallocated list calls POST /api/class-instances/:id/assign.
The list updates immediately on all polling devices (10s poll).&lt;/p&gt;
&lt;p&gt;When teacher locks: unallocated list becomes read-only on group token devices.
Show: “🔒 Groups are locked. Ask your teacher if you need to change groups.”&lt;/p&gt;
&lt;p&gt;Teacher’s allocation view (in the tool instance Groups tab, per class):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;11S1  ·  [🔒 Lock groups]  [Unlock]

UNALLOCATED (3):  Tom P · Sarah K · Amara D
  [Assign Tom P to: Group 1 ▾]  [Mark absent]

GROUP 1  (Navigator, Sketcher, Note-taker, Interviewer)
  ✓ Marcus T — Navigator       [move] [remove]
  ✓ Yemi O   — Sketcher        [move] [remove]
  ○ [empty]  — Note-taker
  ○ [empty]  — Interviewer

GROUP 2 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;“Mark absent” removes from unallocated, sets person node
&lt;code&gt;meta.absent_this_session: true&lt;/code&gt;. Can be reversed.&lt;/p&gt;
&lt;h3&gt;Verify Phase C&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a tool instance with 2 group token codes visible.
Navigate to &lt;code&gt;http://localhost:3000/join&lt;/code&gt; in an incognito window.
Enter the group 1 token. See the allocation view with unallocated students.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tap “Tom P” — Tom moves from unallocated to Group 1 on this device.
Open another incognito window with the Group 2 token.
Within 10 seconds, Tom P is gone from the unallocated list on Group 2’s device.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As facilitator in the main app, move Tom P from Group 1 to Group 2.
Within 10 seconds, Group 1 token device shows Tom P gone from their group.
Group 2 token device shows Tom P in their group.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Facilitator locks the class instance.
Group token devices show the lock icon. Tapping unallocated names does nothing.
Facilitator can still move students. Unlock restores self-assignment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As facilitator, mark Sarah K as absent.
Sarah K disappears from the unallocated list on all devices.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;PHASE D — Cross-Class View &amp;amp; Feedforward to Collate&lt;/h2&gt;
&lt;h3&gt;Tool instance cross-class view&lt;/h3&gt;
&lt;p&gt;When a tool instance has multiple class instances, the tool instance
Contributions tab gains a class-level summary above the existing filters:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CLASSES  2

┌──────────────────────────────────┐  ┌──────────────────────────────────┐
│ 11S1                             │  │ 9J1                              │
│ 6 groups · 18 contributions      │  │ 5 groups · 12 contributions      │
│ ● submitted                      │  │ ○ in progress                    │
│ [View class →]                   │  │ [View class →]                   │
└──────────────────────────────────┘  └──────────────────────────────────┘

CROSS-CLASS VIEW
[ All ] [ 11S1 ] [ 9J1 ]    [ pending ] [ approved ] [ all ]

[contribution cards — filterable by class and approval status]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;“View class →” navigates to the class_instance node (which has its own
dedicated view — same tab pattern as tool instance: Groups / Contributions /
Allocation / Summary).&lt;/p&gt;
&lt;h3&gt;Feedforward to Collate&lt;/h3&gt;
&lt;p&gt;When a Collate phase node is active, the phase panel (from Phase 3) already
shows a “From Gather” section. Extend this to show contributions at the
class instance level:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM GATHER

[ All classes ] [ 11S1 ] [ 9J1 ]    Show: [ approved only ● ] [ all ○ ]

[contribution cards from the matching Gather tool instances]
[each card shows: group name, class name, content preview, approval status]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Collate class instance (when a class does Collate) sees:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Primary: their own class’s approved Gather contributions (auto-surfaced)&lt;/li&gt;
&lt;li&gt;Secondary: other classes’ approved Gather contributions (available to browse
and include via a “bring into our Collate” action)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;“Bring into our Collate” creates a &lt;code&gt;responds_to&lt;/code&gt; relation from the Collate
class instance to the selected Gather contribution node. It appears in their
Collate view marked as “included from [class name]”.&lt;/p&gt;
&lt;h3&gt;Verify Phase D&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Two class instances on one tool instance, both with approved contributions.
Tool instance Contributions tab shows the class summary cards with counts.
Class filter tabs show contributions from each class separately.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Navigate to a Collate phase node. “From Gather” section shows contributions
filterable by class. 11S1’s contributions are shown by default.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click “bring into our Collate” on a 9J1 contribution.
It appears in the Collate view marked “included from 9J1”.
A responds_to relation is created in the graph.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;What does NOT change&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Reference instance — unchanged&lt;/li&gt;
&lt;li&gt;Auth system (except adding group_token role) — unchanged&lt;/li&gt;
&lt;li&gt;Image maps — unchanged&lt;/li&gt;
&lt;li&gt;Temporal navigation — unchanged&lt;/li&gt;
&lt;li&gt;Standard node view — unchanged (accessible via node view ↗ on all custom views)&lt;/li&gt;
&lt;li&gt;Quick capture — unchanged&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;File changes&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;db/database.js          — migrations table, inst_hierarchy_v1,
                          project_container_v1, group token generation
api/institutions.js     — POST /api/institutions (new)
api/class-instances.js  — GET/POST allocation, assign, unassign, lock (new)
api/auth.js             — group_token role, POST /api/token-login (new)
api/tool-instances.js   — class_instance creation, regenerate-groups update
api/projects.js         — institution scoping enforcement, assigned_classes
server.js               — mount new routers, serve /join route
lfti-spine.html         — class assignment in Setup tab, cross-class view,
                          teacher allocation view, feedforward Collate section,
                          container node rendering
public/join.html        — NEW: minimal token login page (separate from main app)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: &lt;code&gt;/join&lt;/code&gt; is a separate minimal HTML file served at that route.
It does not share the main app’s JS — it only needs: token input,
POST /api/token-login, allocation polling (GET /api/class-instances/:id/allocation),
assign/unassign calls, and a simple contribution upload for when allocation is done.
Keep it under 400 lines. Style to match the main app’s design tokens via a
shared CSS variables approach (serve the same CSS variables, minimal additional styles).&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;When you’re done — full verification&lt;/h2&gt;
&lt;p&gt;Run through this sequence across multiple browser windows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phase A:&lt;/strong&gt; Superadmin creates Bristol Academy. Staff/Students/Projects
containers appear. Bristol Academy admin logs in, can only create projects
under Bristol Academy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phase B:&lt;/strong&gt; Project wizard pre-selects assigned classes. Tool instance
Setup tab shows class assignment section. Adding 11S1 creates a class_instance
with group children. Removing it (after confirmation) cleans up completely.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phase C:&lt;/strong&gt; Two group tokens visible on a tool instance. Navigate to /join
in incognito. Enter token. See allocation view. Self-assign. Second incognito
window with other group token sees the change within 10 seconds. Facilitator
locks — self-assignment blocked on token devices.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Phase D:&lt;/strong&gt; Two classes with approved contributions on one tool instance.
Cross-class summary cards visible. Collate phase feedforward shows both classes’
contributions filterable and includable.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>Minimal authentication system</title>
    <link href="https://themetalevel.org/notes/lfti-auth/"/>
    <updated>2026-05-21T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/lfti-auth/</id>
    <summary>This prompt adds user authentication to the LFTI spine. Read the existing codebase fully before starting — particularly server.js, db/database.js, and api/nodes.js.</summary>
    <content type="html">&lt;p&gt;This prompt adds user authentication to the LFTI spine. Read the existing codebase fully before starting — particularly &lt;code&gt;server.js&lt;/code&gt;, &lt;code&gt;db/database.js&lt;/code&gt;, and &lt;code&gt;api/nodes.js&lt;/code&gt;. Understand what exists before adding to it.&lt;/p&gt;
&lt;p&gt;The goal is the smallest correct auth system that supports role-based access and institution scoping, is easy to extend later, and doesn’t break anything currently working.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Design principles (do not violate)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Simple over complete.&lt;/strong&gt; No OAuth, no email verification, no password reset flow yet. Those come later. Build what’s needed now.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Additive only.&lt;/strong&gt; Nothing currently working should break. The API endpoints continue to work. The frontend continues to load. Auth wraps the existing system, it doesn’t replace it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Users are also nodes.&lt;/strong&gt; Every user has a corresponding node in the graph with &lt;code&gt;type: &amp;quot;person&amp;quot;&lt;/code&gt;. The user table is the auth layer only — all relationships live in the graph.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Escape hatch preserved.&lt;/strong&gt; The &lt;code&gt;meta{}&lt;/code&gt; field on the user table follows the same convention as nodes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local dev friendly.&lt;/strong&gt; Must be testable with multiple users from one machine using different browsers or incognito windows.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Database changes&lt;/h2&gt;
&lt;p&gt;Add to &lt;code&gt;db/database.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE TABLE IF NOT EXISTS users (
  id             TEXT PRIMARY KEY,
  name           TEXT NOT NULL,
  email          TEXT UNIQUE NOT NULL,
  password_hash  TEXT NOT NULL,
  role           TEXT NOT NULL DEFAULT &#39;student&#39;,
  institution_id TEXT,
  node_id        TEXT,
  created_at     TEXT NOT NULL,
  meta           TEXT DEFAULT &#39;{}&#39;
);

CREATE TABLE IF NOT EXISTS sessions (
  token          TEXT PRIMARY KEY,
  user_id        TEXT NOT NULL,
  created_at     TEXT NOT NULL,
  expires_at     TEXT NOT NULL,
  FOREIGN KEY (user_id) REFERENCES users(id)
);

CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id);
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Roles&lt;/strong&gt; (stored as strings, checked in middleware):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;superadmin&lt;/code&gt; — sees everything, can create institutions and users&lt;/li&gt;
&lt;li&gt;&lt;code&gt;institution_admin&lt;/code&gt; — manages their institution’s projects and users&lt;/li&gt;
&lt;li&gt;&lt;code&gt;facilitator&lt;/code&gt; — runs sessions within projects they’re assigned to&lt;/li&gt;
&lt;li&gt;&lt;code&gt;student&lt;/code&gt; — contributes to sessions they’re part of&lt;/li&gt;
&lt;li&gt;&lt;code&gt;observer&lt;/code&gt; — read-only access to approved artefacts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Password hashing:&lt;/strong&gt; Use &lt;code&gt;bcrypt&lt;/code&gt; with 10 salt rounds. Add &lt;code&gt;bcrypt&lt;/code&gt; to package.json dependencies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Session tokens:&lt;/strong&gt; Generate with &lt;code&gt;crypto.randomBytes(32).toString(&#39;hex&#39;)&lt;/code&gt;. Sessions expire after 7 days. Clean up expired sessions on server start.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Seed users for development&lt;/h2&gt;
&lt;p&gt;On first run (if users table is empty), seed these development users automatically so the system is immediately testable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const devUsers = [
  {
    id: &#39;user_superadmin&#39;,
    name: &#39;Super Admin&#39;,
    email: &#39;admin@lfti.dev&#39;,
    password: &#39;lfti-admin&#39;,
    role: &#39;superadmin&#39;,
    institution_id: null,
    node_id: &#39;person_admin&#39;
  },
  {
    id: &#39;user_uk_admin&#39;,
    name: &#39;UK School Admin&#39;,
    email: &#39;ukadmin@lfti.dev&#39;,
    password: &#39;lfti-uk&#39;,
    role: &#39;institution_admin&#39;,
    institution_id: &#39;uk&#39;,       // matches existing institution node
    node_id: &#39;person_uk_admin&#39;
  },
  {
    id: &#39;user_facilitator&#39;,
    name: &#39;James (Facilitator)&#39;,
    email: &#39;facilitator@lfti.dev&#39;,
    password: &#39;lfti-facilitator&#39;,
    role: &#39;facilitator&#39;,
    institution_id: &#39;uk&#39;,
    node_id: &#39;person_facilitator&#39;
  },
  {
    id: &#39;user_student_1&#39;,
    name: &#39;Student One (UK)&#39;,
    email: &#39;student1@lfti.dev&#39;,
    password: &#39;lfti-student&#39;,
    role: &#39;student&#39;,
    institution_id: &#39;uk&#39;,
    node_id: &#39;person_student_1&#39;
  },
  {
    id: &#39;user_zm_admin&#39;,
    name: &#39;Kamoto Admin&#39;,
    email: &#39;zmadmin@lfti.dev&#39;,
    password: &#39;lfti-zm&#39;,
    role: &#39;institution_admin&#39;,
    institution_id: &#39;zm&#39;,       // matches existing institution node
    node_id: &#39;person_zm_admin&#39;
  },
  {
    id: &#39;user_observer&#39;,
    name: &#39;Observer (Funder)&#39;,
    email: &#39;observer@lfti.dev&#39;,
    password: &#39;lfti-observer&#39;,
    role: &#39;observer&#39;,
    institution_id: null,
    node_id: &#39;person_observer&#39;
  }
];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Print all dev credentials to the console on first seed so they’re easy to find:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;╔══════════════════════════════════════════╗
║     LFTI Dev Users — First Run Seed      ║
╠══════════════════════════════════════════╣
║ superadmin      admin@lfti.dev           ║
║ institution_admin ukadmin@lfti.dev       ║
║ facilitator     facilitator@lfti.dev     ║
║ student         student1@lfti.dev        ║
║ zm admin        zmadmin@lfti.dev         ║
║ observer        observer@lfti.dev        ║
║ (all passwords in db/database.js seed)   ║
╚══════════════════════════════════════════╝
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also create corresponding person nodes in the graph for each dev user, with &lt;code&gt;involves&lt;/code&gt; relations to their institution nodes where applicable.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;New files&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;api/auth.js&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Handles all auth routes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /api/auth/login
  body: { email, password }
  response: { user: { id, name, role, institution_id, node_id }, token }
  sets httpOnly cookie: lfti_session=&amp;lt;token&amp;gt;
  on failure: 401 { error: &amp;quot;Invalid credentials&amp;quot; }

POST /api/auth/logout
  clears cookie, deletes session token from db
  response: { ok: true }

GET /api/auth/me
  reads cookie, returns current user or 401
  response: { user: { id, name, role, institution_id, node_id } }
  this is what the frontend calls on boot to check if logged in
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cookie settings:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;res.cookie(&#39;lfti_session&#39;, token, {
  httpOnly: true,
  sameSite: &#39;lax&#39;,
  maxAge: 7 * 24 * 60 * 60 * 1000,  // 7 days in ms
  // secure: true  // uncomment when running over HTTPS
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;middleware/auth.js&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Two middleware functions used by API routes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// requireAuth — rejects unauthenticated requests
function requireAuth(req, res, next) { ... }

// requireRole(...roles) — rejects users without matching role
function requireRole(...roles) {
  return (req, res, next) =&amp;gt; { ... }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both attach &lt;code&gt;req.user&lt;/code&gt; (the full user row) when successful.&lt;/p&gt;
&lt;p&gt;Usage in routes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const { requireAuth, requireRole } = require(&#39;../middleware/auth&#39;);

router.get(&#39;/api/nodes&#39;, requireAuth, (req, res) =&amp;gt; { ... });
router.delete(&#39;/api/nodes/:id&#39;, requireAuth, requireRole(&#39;facilitator&#39;, &#39;institution_admin&#39;, &#39;superadmin&#39;), (req, res) =&amp;gt; { ... });
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Institution scoping&lt;/h2&gt;
&lt;p&gt;When a non-superadmin user requests nodes, filter by institution visibility:&lt;/p&gt;
&lt;p&gt;A node is visible to a user if ANY of the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The node’s &lt;code&gt;meta._visibility&lt;/code&gt; is &lt;code&gt;&amp;quot;public&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;portal&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The node’s &lt;code&gt;meta._visibility&lt;/code&gt; is &lt;code&gt;&amp;quot;partners&amp;quot;&lt;/code&gt; and the user’s institution has an &lt;code&gt;involves&lt;/code&gt; or &lt;code&gt;responds_to&lt;/code&gt; relation to the node or its project ancestor&lt;/li&gt;
&lt;li&gt;The node has no &lt;code&gt;_visibility&lt;/code&gt; set (defaults to private) AND the node belongs to the user’s institution (determined by traversing &lt;code&gt;contains&lt;/code&gt; relations up to an institution node)&lt;/li&gt;
&lt;li&gt;The user is &lt;code&gt;superadmin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The node’s &lt;code&gt;meta._level&lt;/code&gt; is &lt;code&gt;&amp;quot;reference&amp;quot;&lt;/code&gt; (reference nodes are always visible to authenticated users)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Implementation:&lt;/strong&gt; Add a &lt;code&gt;filterNodesByVisibility(nodes, user)&lt;/code&gt; function in &lt;code&gt;db/database.js&lt;/code&gt;. Call it in &lt;code&gt;GET /api/nodes&lt;/code&gt; after fetching all nodes.&lt;/p&gt;
&lt;p&gt;For this first pass, implement rules 1, 4, 5, and a simplified version of 3 (nodes whose &lt;code&gt;institution_id&lt;/code&gt; meta field matches the user’s institution_id). Rules 2 and the full graph traversal version of 3 can come later — add a comment marking where that logic goes.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Frontend changes&lt;/h2&gt;
&lt;h3&gt;Login screen&lt;/h3&gt;
&lt;p&gt;When the app loads and &lt;code&gt;GET /api/auth/me&lt;/code&gt; returns 401, show a login screen instead of the main UI. The login screen replaces the full app — not a modal, not an overlay, a full page replacement.&lt;/p&gt;
&lt;p&gt;Login screen elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LFTI logo / wordmark (same styling as the header)&lt;/li&gt;
&lt;li&gt;Email input&lt;/li&gt;
&lt;li&gt;Password input&lt;/li&gt;
&lt;li&gt;Login button&lt;/li&gt;
&lt;li&gt;Error message area (shows “Invalid credentials” on failure)&lt;/li&gt;
&lt;li&gt;No registration link — accounts are created by admins&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On successful login: hide login screen, show main app, initialise normally (call &lt;code&gt;loadDB()&lt;/code&gt; etc.)&lt;/p&gt;
&lt;p&gt;Style to match existing design language exactly — &lt;code&gt;var(--bg)&lt;/code&gt;, &lt;code&gt;var(--surface)&lt;/code&gt;, &lt;code&gt;var(--accent)&lt;/code&gt;, &lt;code&gt;var(--mono)&lt;/code&gt; font. The login screen should feel like part of the same system, not a different product.&lt;/p&gt;
&lt;h3&gt;User context in the app&lt;/h3&gt;
&lt;p&gt;After login, the frontend holds the current user in state:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;state.currentUser = {
  id, name, role, institution_id, node_id
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use this to:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Show/hide controls based on role:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Delete button in footer: hide for &lt;code&gt;student&lt;/code&gt; and &lt;code&gt;observer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+ capture&lt;/code&gt; button: hide for &lt;code&gt;observer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Type pills: hide for &lt;code&gt;observer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+ map image&lt;/code&gt; button: hide for &lt;code&gt;observer&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Show user identity in the header:&lt;/strong&gt;
Add a small user indicator to the right of the header (before the search input):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[role badge] [name]  [logout]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Role badge styling:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;superadmin&lt;/code&gt; → accent colour&lt;/li&gt;
&lt;li&gt;&lt;code&gt;institution_admin&lt;/code&gt; → muted blue&lt;/li&gt;
&lt;li&gt;&lt;code&gt;facilitator&lt;/code&gt; → muted orange&lt;/li&gt;
&lt;li&gt;&lt;code&gt;student&lt;/code&gt; → muted green&lt;/li&gt;
&lt;li&gt;&lt;code&gt;observer&lt;/code&gt; → text-dim&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Logout:&lt;/strong&gt; clicking logout calls &lt;code&gt;POST /api/auth/logout&lt;/code&gt;, clears &lt;code&gt;state.currentUser&lt;/code&gt;, shows login screen.&lt;/p&gt;
&lt;h3&gt;API calls with auth&lt;/h3&gt;
&lt;p&gt;All existing &lt;code&gt;fetch&lt;/code&gt; calls to &lt;code&gt;/api/&lt;/code&gt; already work with cookies because cookies are sent automatically with same-origin requests. No changes needed to the fetch calls themselves — the &lt;code&gt;httpOnly&lt;/code&gt; cookie is sent by the browser on every request.&lt;/p&gt;
&lt;p&gt;However: wrap the boot sequence so it waits for &lt;code&gt;GET /api/auth/me&lt;/code&gt; before calling &lt;code&gt;loadDB()&lt;/code&gt;. If auth fails, show login screen. If auth succeeds, store user in state and proceed normally.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;async function boot() {
  try {
    const res = await fetch(&#39;/api/auth/me&#39;);
    if (!res.ok) { showLoginScreen(); return; }
    const { user } = await res.json();
    state.currentUser = user;
    seedLFTI();
    seedReferenceInstance();
    loadDB();
    saveDB();
    renderTree();
    updateStatus();
    renderTemporalNav();
    renderUserBadge();
  } catch(e) {
    showLoginScreen();
  }
}

boot();
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Route protection in server.js&lt;/h2&gt;
&lt;p&gt;Apply &lt;code&gt;requireAuth&lt;/code&gt; to all &lt;code&gt;/api/nodes&lt;/code&gt; routes.
Apply &lt;code&gt;requireAuth&lt;/code&gt; to all &lt;code&gt;/api/images&lt;/code&gt; routes.
Leave &lt;code&gt;/api/auth/login&lt;/code&gt; and &lt;code&gt;/api/auth/logout&lt;/code&gt; and &lt;code&gt;/api/auth/me&lt;/code&gt; unprotected (they are the auth routes themselves).
Leave the static file serving (the HTML file) unprotected — the frontend handles the auth check on load.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;package.json additions&lt;/h2&gt;
&lt;p&gt;Add one dependency:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;bcrypt&amp;quot;: &amp;quot;^5.1.1&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No other new packages. &lt;code&gt;crypto&lt;/code&gt; is built into Node.js.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;File structure after this prompt&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;/
├── api/
│   ├── nodes.js         (modified — add requireAuth)
│   ├── images.js        (modified — add requireAuth)
│   └── auth.js          (new)
├── middleware/
│   └── auth.js          (new)
├── db/
│   └── database.js      (modified — users table, sessions table, dev seed)
├── codeReference/
│   └── ...              (unchanged)
├── server.js            (modified — mount auth routes, apply middleware)
└── lfti-spine.html      (modified — login screen, boot sequence, user badge)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Testing checklist — do all six before finishing&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open Chrome. Go to &lt;code&gt;http://localhost:3000&lt;/code&gt;. See login screen (not the app).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Login as &lt;code&gt;admin@lfti.dev&lt;/code&gt; / &lt;code&gt;lfti-admin&lt;/code&gt;. See the app with &lt;code&gt;superadmin&lt;/code&gt; badge in header. All controls visible. All nodes visible including reference instance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open Firefox (or incognito). Login as &lt;code&gt;student1@lfti.dev&lt;/code&gt; / &lt;code&gt;lfti-student&lt;/code&gt;. See app with &lt;code&gt;student&lt;/code&gt; badge. Delete button hidden. Capture button visible. Only UK institution nodes visible (not Zambia private nodes).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open Edge (or second incognito). Login as &lt;code&gt;observer@lfti.dev&lt;/code&gt; / &lt;code&gt;lfti-observer&lt;/code&gt;. See app with &lt;code&gt;observer&lt;/code&gt; badge. Delete hidden, capture hidden, type pills hidden. Only public/portal visibility nodes visible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click logout in any browser. Login screen appears. App state is cleared.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Close browser entirely (not just the tab). Reopen &lt;code&gt;http://localhost:3000&lt;/code&gt;. Session cookie persists — app loads directly without login screen (7-day cookie). Verify correct user is still recognised via &lt;code&gt;GET /api/auth/me&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  <entry>
    <title>Phase 3 — project dashboard and tool selection</title>
    <link href="https://themetalevel.org/notes/lfti-phase-3/"/>
    <updated>2026-05-21T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/lfti-phase-3/</id>
    <summary>This prompt builds on the completed project setup wizard. Read the full codebase before starting.</summary>
    <content type="html">&lt;p&gt;This prompt builds on the completed project setup wizard. Read the full codebase before starting.
Understand the existing node structure, the phase node meta fields (movement, phase, status),
the reference instance tool nodes, and the current content section rendering in lfti-spine.html.&lt;/p&gt;
&lt;p&gt;This prompt has two distinct pieces:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Project node → dashboard view&lt;/li&gt;
&lt;li&gt;Phase node → tool browser + session launcher&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Build and verify piece 1 before starting piece 2.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;PIECE 1 — Project Dashboard&lt;/h2&gt;
&lt;p&gt;When a node of type &lt;code&gt;project&lt;/code&gt; is selected, render a dashboard instead of the standard
parents/this node/children layout. The standard layout remains accessible via a small
“← node view” link in the dashboard header for power users.&lt;/p&gt;
&lt;h3&gt;Dashboard layout&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│ [Project title]                    [● Active]  [node view ↗]   │
│ [institution name] · [date range] · [format]                    │
├─────────────────────────────────────────────────────────────────┤
│ TABS: [ Overview ] [ Approvals n ] [ Participants ] [ Settings ]│
├─────────────────────────────────────────────────────────────────┤
│ [tab content — see below]                                        │
└─────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Status badge colours (using existing CSS variables):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;not_started&lt;/code&gt; → &lt;code&gt;var(--text-dim)&lt;/code&gt; · label: “Not started”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;active&lt;/code&gt; → &lt;code&gt;var(--accent)&lt;/code&gt; · label: “Active”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;complete&lt;/code&gt; → muted blue · label: “Complete”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;archived&lt;/code&gt; → &lt;code&gt;var(--text-dim)&lt;/code&gt; · label: “Archived”&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Overview tab&lt;/h3&gt;
&lt;p&gt;Three sections:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Progress grid:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PROGRESS

              Gather          Collate         Present
Past          [●●●○○  3]     [○○○○○  0]     [○○○○○  0]
Situation     [○○○○○  0]     [○○○○○  0]     [○○○○○  0]
Futures       [○○○○○  0]     [○○○○○  0]     [○○○○○  0]
Whole         [○○○○○  0]     [○○○○○  0]     [○○○○○  0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each cell is clickable — navigates to that phase node via selectNode().
The number shown is the count of direct child nodes of that phase node
(i.e. contribution/artefact nodes created under it).
Filled dots scale: 0=empty, 1-2=one dot, 3-4=two dots, 5+=three dots
(out of five dot positions).&lt;/p&gt;
&lt;p&gt;Each cell has a subtle status colour:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No children, no tool selected → dim (not started)&lt;/li&gt;
&lt;li&gt;Tool selected but no contributions → amber (in progress / waiting)&lt;/li&gt;
&lt;li&gt;Has contributions, not approved → amber&lt;/li&gt;
&lt;li&gt;Has approved contributions → accent green&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Needs attention:&lt;/strong&gt;
A list of items requiring action from this user. Only show items relevant
to their role. Empty state: “Nothing needs attention right now.”&lt;/p&gt;
&lt;p&gt;Items to surface:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“n contributions awaiting approval” → links to Approvals tab&lt;/li&gt;
&lt;li&gt;“[Phase name] has no tool selected” → links to that phase node&lt;/li&gt;
&lt;li&gt;“Workshop date [date] is tomorrow — [phase] is not started”&lt;/li&gt;
&lt;li&gt;“Partner institution has shared new content” (when interchange exists)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each item has a small arrow link → navigating to the relevant node or tab.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Participants summary:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PARTICIPANTS
  2 staff  ·  2 classes (11S1, 9J1)  ·  ~30 students
  [ Manage participants → ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Manage participants link navigates to the Participants tab.&lt;/p&gt;
&lt;h3&gt;Approvals tab&lt;/h3&gt;
&lt;p&gt;Only visible to facilitator, institution_admin, superadmin roles.
Badge on tab shows count of pending approvals.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Standard mode (default):&lt;/strong&gt;
A list of pending contributions. Each item shows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Group name / contributor&lt;/li&gt;
&lt;li&gt;Phase (e.g. “Past — Gather”)&lt;/li&gt;
&lt;li&gt;Tool used&lt;/li&gt;
&lt;li&gt;Timestamp&lt;/li&gt;
&lt;li&gt;Content preview (title + first line of body, or thumbnail if image)&lt;/li&gt;
&lt;li&gt;[ Approve ] [ Flag ] buttons&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Approve: sets &lt;code&gt;node.meta.approval_status = &amp;quot;approved&amp;quot;&lt;/code&gt;, saves via PUT /api/nodes/:id
Flag: opens a small inline text field for a note, sets &lt;code&gt;node.meta.approval_status = &amp;quot;flagged&amp;quot;&lt;/code&gt;,
sets &lt;code&gt;node.meta.flag_note = &amp;quot;[text]&amp;quot;&lt;/code&gt;, saves. Flagged content is visible to the group
with the note displayed.&lt;/p&gt;
&lt;p&gt;Empty state: “No contributions awaiting approval.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Live session mode:&lt;/strong&gt;
A toggle button in the top right of the Approvals tab: “[ ○ Live mode ]”
When activated:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tab background shifts slightly (subtle amber tint on the tab itself)&lt;/li&gt;
&lt;li&gt;List becomes a real-time feed — poll GET /api/projects/:id/pending every 5 seconds&lt;/li&gt;
&lt;li&gt;New items animate in at the top&lt;/li&gt;
&lt;li&gt;Approve button is larger and more prominent&lt;/li&gt;
&lt;li&gt;A “Live session active” indicator appears in the header status area&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add endpoint:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET /api/projects/:id/pending
  Returns all child nodes of this project&#39;s phase nodes where 
  meta.approval_status is null or &amp;quot;pending&amp;quot;
  Ordered by created_at desc
  Auth: facilitator+ only
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Participants tab&lt;/h3&gt;
&lt;p&gt;Three sections matching the wizard Step 3:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Staff &amp;amp; facilitators&lt;/strong&gt; — list with role badge, remove button
&lt;strong&gt;Classes&lt;/strong&gt; — list with class name, teacher, student count, remove button
&lt;strong&gt;Groups&lt;/strong&gt; — auto-suggested groups per class, editable names&lt;/p&gt;
&lt;p&gt;&lt;code&gt;+ Add staff&lt;/code&gt;, &lt;code&gt;+ Add class&lt;/code&gt; buttons open small inline forms (not the full wizard).
Changes save immediately via PUT /api/nodes/:id on the relevant person/session node.&lt;/p&gt;
&lt;h3&gt;Settings tab&lt;/h3&gt;
&lt;p&gt;Editable fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Project name&lt;/li&gt;
&lt;li&gt;Description&lt;/li&gt;
&lt;li&gt;Date range (start/end)&lt;/li&gt;
&lt;li&gt;Workshop dates (add/remove)&lt;/li&gt;
&lt;li&gt;Approval mode toggle (Standard / Live)&lt;/li&gt;
&lt;li&gt;Group contribution limit (number input)&lt;/li&gt;
&lt;li&gt;Archive project button (sets status to archived, confirms first)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All changes save via PUT /api/nodes/:id on the project node’s meta.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;PIECE 2 — Phase Node: Tool Browser &amp;amp; Session Launcher&lt;/h2&gt;
&lt;p&gt;When a node with &lt;code&gt;meta.phase&lt;/code&gt; set (gather/collate/present) is selected,
replace the empty children section with a purposeful phase panel.&lt;/p&gt;
&lt;h3&gt;Phase panel layout&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│ PAST — GATHER                                    [status badge] │
│ Students explore and capture their experience of the past.      │
│ (pulled from the matching reference phase node body)            │
├─────────────────────────────────────────────────────────────────┤
│ TOOLS FOR THIS PHASE                                            │
│                                                                 │
│ Filters: [Individual] [Group] [Indoors] [Outdoors] [Async]     │
│          [Sync] [&amp;lt; 30min] [30-60min] [60min+]                  │
│          [Low-tech] [High-tech]                                 │
│                                                                 │
│ [tool card] [tool card] [tool card]                             │
│ [tool card] [tool card] [+ more]                                │
│                                                                 │
│ Selected: Body Map ×   Story Circle ×   [+ add another]        │
│                                                                 │
│ [ Start this phase → ]  (appears when ≥1 tool selected)        │
├─────────────────────────────────────────────────────────────────┤
│ CONTRIBUTIONS  0                                                │
│ (empty state until session is started)                          │
└─────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Tool cards&lt;/h3&gt;
&lt;p&gt;Each card represents a reference tool node matching this phase.
Pull tool nodes from the reference instance where &lt;code&gt;meta.phase&lt;/code&gt; matches
the current phase node’s &lt;code&gt;meta.phase&lt;/code&gt; value.&lt;/p&gt;
&lt;p&gt;Card shows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tool title (truncated if long)&lt;/li&gt;
&lt;li&gt;2-line description excerpt from node body&lt;/li&gt;
&lt;li&gt;Small badges: individual/group, indoor/outdoor, time estimate&lt;/li&gt;
&lt;li&gt;Selected state: accent border + checkmark when selected&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Clicking a card toggles selection.
Maximum selection: no hard limit, but after 3 selected show a gentle nudge:
“You have 3 tools selected — that’s a full session. Add more if you need,
or start now.” The nudge disappears after 5 seconds or on dismissal.&lt;/p&gt;
&lt;h3&gt;Tool filters&lt;/h3&gt;
&lt;p&gt;Filter buttons are toggle pills above the tool grid. Multiple can be active
simultaneously — show tools matching ALL active filters (AND logic).
Clearing all filters shows all tools for this phase.&lt;/p&gt;
&lt;p&gt;Filter values come from tool node meta fields. Add these meta fields to
reference tool nodes during this prompt (update the existing seeded nodes):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;meta&amp;quot;: {
  &amp;quot;_level&amp;quot;: &amp;quot;reference&amp;quot;,
  &amp;quot;_visibility&amp;quot;: &amp;quot;public&amp;quot;,
  &amp;quot;phase&amp;quot;: &amp;quot;gather&amp;quot;,
  &amp;quot;format&amp;quot;: [&amp;quot;group&amp;quot;, &amp;quot;individual&amp;quot;],       // can be both
  &amp;quot;location&amp;quot;: [&amp;quot;indoors&amp;quot;, &amp;quot;outdoors&amp;quot;],     // can be both  
  &amp;quot;modality&amp;quot;: [&amp;quot;sync&amp;quot;, &amp;quot;async&amp;quot;],           // can be both
  &amp;quot;duration&amp;quot;: &amp;quot;60min+&amp;quot;,                    // &amp;quot;&amp;lt; 30min&amp;quot; | &amp;quot;30-60min&amp;quot; | &amp;quot;60min+&amp;quot;
  &amp;quot;tech_level&amp;quot;: &amp;quot;low&amp;quot;                      // &amp;quot;low&amp;quot; | &amp;quot;high&amp;quot; | &amp;quot;both&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Update all reference tool nodes with appropriate values based on
PLA_TOOLS_REFERENCE.md descriptions. Do not guess — if a field is
genuinely ambiguous for a tool, use both values or omit the filter tag.&lt;/p&gt;
&lt;h3&gt;Starting a phase&lt;/h3&gt;
&lt;p&gt;“Start this phase →” button:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Sets &lt;code&gt;phase_node.meta.status = &amp;quot;active&amp;quot;&lt;/code&gt;, saves&lt;/li&gt;
&lt;li&gt;Sets &lt;code&gt;phase_node.meta.selected_tools = [&amp;quot;ref_g_body_map&amp;quot;, &amp;quot;ref_g_story_circle&amp;quot;]&lt;/code&gt;
(array of selected reference tool node ids)&lt;/li&gt;
&lt;li&gt;Adds &lt;code&gt;references&lt;/code&gt; relations from phase node to each selected tool node&lt;/li&gt;
&lt;li&gt;Shows the contributions area (was empty/hidden before)&lt;/li&gt;
&lt;li&gt;Updates the project dashboard progress grid cell for this phase to amber&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The phase node now shows the session launcher area below the tool section:&lt;/p&gt;
&lt;h3&gt;Contributions area (after phase started)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CONTRIBUTIONS  0          [ + Add contribution ]   [ ⚡ Live mode ]

Groups:  [ All ] [ Group 1 ] [ Group 2 ] [ Group 3 ]

(empty state)
&amp;quot;No contributions yet. Groups can add their work using the button above 
or from their own view.&amp;quot;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;+ Add contribution&lt;/code&gt; button: opens the quick-capture overlay pre-configured
for this phase — type set to &lt;code&gt;artefact&lt;/code&gt;, parent set to this phase node,
&lt;code&gt;meta.phase&lt;/code&gt; and &lt;code&gt;meta.movement&lt;/code&gt; inherited, &lt;code&gt;meta.approval_status = &amp;quot;pending&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Group filter tabs: filter displayed contributions by the contributing group node.&lt;/p&gt;
&lt;p&gt;Each contribution card shows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Title&lt;/li&gt;
&lt;li&gt;Contributor (group name)&lt;/li&gt;
&lt;li&gt;Timestamp&lt;/li&gt;
&lt;li&gt;Approval status badge: pending / approved / flagged&lt;/li&gt;
&lt;li&gt;If flagged: the flag note&lt;/li&gt;
&lt;li&gt;Click → selectNode() to view the full contribution node&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For facilitator/admin: Approve and Flag buttons inline on each card.
For students: their own group’s contributions only, with approval status visible.&lt;/p&gt;
&lt;h3&gt;Collate phase special behaviour&lt;/h3&gt;
&lt;p&gt;When &lt;code&gt;meta.phase === &amp;quot;collate&amp;quot;&lt;/code&gt;, the tool browser shows Collate tools.
Additionally, above the tool browser, show a “From Gather” section:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM GATHER
[contribution card] [contribution card] [contribution card]
(approved contributions from the matching Gather phase node)
&amp;quot;These are the findings your group produced in Gather. 
Use them as the starting point for Collate.&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pull these by finding the sibling Gather phase node
(same movement, phase: “gather”) and showing its approved children.&lt;/p&gt;
&lt;h3&gt;Present phase special behaviour&lt;/h3&gt;
&lt;p&gt;When &lt;code&gt;meta.phase === &amp;quot;present&amp;quot;&lt;/code&gt;, the tool browser shows Present tools.
Additionally, above the tool browser, show a “From Collate” section
showing approved Collate outputs, same pattern as above.&lt;/p&gt;
&lt;p&gt;If a partner institution exists on this project, show:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXCHANGE
This project is paired with [partner institution].
Approved Present artefacts will be visible to them.
[ View their Present artefacts → ]  (links to partner&#39;s present phase node)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Reference tool node meta updates&lt;/h2&gt;
&lt;p&gt;Update ALL reference tool nodes in the database with appropriate filter
meta values. Do this via a migration script &lt;code&gt;scripts/update_tool_meta.js&lt;/code&gt;
that can be run with &lt;code&gt;node scripts/update_tool_meta.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Use these values as a guide (fill in all tools from PLA_TOOLS_REFERENCE.md):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;format&lt;/th&gt;
&lt;th&gt;location&lt;/th&gt;
&lt;th&gt;modality&lt;/th&gt;
&lt;th&gt;duration&lt;/th&gt;
&lt;th&gt;tech_level&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Observation&lt;/td&gt;
&lt;td&gt;individual&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Semi-structured interview&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;60min+&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transect walk&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;outdoors&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;60min+&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Body map&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;indoors&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;60min+&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Photo walk&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Story circle&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;indoors&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;River of life&lt;/td&gt;
&lt;td&gt;individual&lt;/td&gt;
&lt;td&gt;indoors&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peer interview&lt;/td&gt;
&lt;td&gt;individual&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning journal&lt;/td&gt;
&lt;td&gt;individual&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;async&lt;/td&gt;
&lt;td&gt;&amp;lt;30min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timeline&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;indoors&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Focus group&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;indoors&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;60min+&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pre-perceptions&lt;/td&gt;
&lt;td&gt;individual&lt;/td&gt;
&lt;td&gt;indoors&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;&amp;lt;30min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stones in circles&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Matrix ranking&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pairwise ranking&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;indoors&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Body voting&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;&amp;lt;30min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Affinity grouping&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;indoors&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Venn diagram&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;60min+&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Causal flow diagram&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;60min+&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spectrum line&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;&amp;lt;30min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Most significant change&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live performance&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;60min+&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transect walk as presentation&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;outdoors&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;60min+&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exhibition&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;60min+&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short video&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;async&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Podcast&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;async&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zine&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;indoors&lt;/td&gt;
&lt;td&gt;async&lt;/td&gt;
&lt;td&gt;60min+&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Story of self&lt;/td&gt;
&lt;td&gt;individual&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;&amp;lt;30min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pre-perceptions delta&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;indoors&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hot seating&lt;/td&gt;
&lt;td&gt;group&lt;/td&gt;
&lt;td&gt;indoors&lt;/td&gt;
&lt;td&gt;sync&lt;/td&gt;
&lt;td&gt;30-60min&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;New API endpoints&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;GET /api/projects/:id/pending
  Returns pending contributions for facilitator approval
  Auth: facilitator+

GET /api/projects/:id/progress  
  Returns contribution counts per phase for the progress grid
  { past_gather: 3, past_collate: 0, ... }
  Auth: any authenticated user with access to this project
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;What does NOT change&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Tree navigation, position mode, graph mode — unchanged&lt;/li&gt;
&lt;li&gt;Quick capture overlay (used as base for contribution capture) — unchanged&lt;/li&gt;
&lt;li&gt;Auth system — unchanged&lt;/li&gt;
&lt;li&gt;Reference instance nodes (except adding filter meta fields) — otherwise unchanged&lt;/li&gt;
&lt;li&gt;Standard node view for non-project, non-phase nodes — unchanged&lt;/li&gt;
&lt;li&gt;Image maps, temporal nav — unchanged&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;File changes&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;lfti-spine.html     — project dashboard UI, phase panel UI
api/projects.js     — add /pending and /progress endpoints  
scripts/
  update_tool_meta.js  — one-time migration to add filter meta to tool nodes
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;When you’re done — test in order&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Click the project node as ukadmin. See the dashboard with Overview tab showing
the progress grid (all empty/dim), no needs-attention items, participant summary.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click “Past — Gather” phase node. See the tool browser with filter pills and
tool cards. Click “Group” filter — only group tools remain. Click a tool card
to select it. Select two more. See the nudge appear. See “Start this phase →” button.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click “Start this phase →”. Phase status changes to active. Progress grid cell
updates to amber. Contributions area appears (empty).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click “+ Add contribution”. Quick-capture opens pre-filled for this phase.
Save a test contribution. It appears in the contributions area with “pending” badge.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As ukadmin in the dashboard Approvals tab, see the pending contribution.
Click Approve. Contribution badge changes to “approved”.
Progress grid cell updates to green.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Navigate to “Past — Collate”. See the “From Gather” section showing the
approved contribution from step 5.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  <entry>
    <title>Project setup flow</title>
    <link href="https://themetalevel.org/notes/lfti-project-setup/"/>
    <updated>2026-05-21T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/lfti-project-setup/</id>
    <summary>This prompt builds the guided project setup experience for new institutional users. Read the full codebase before starting — particularly the existing node structure, the auth…</summary>
    <content type="html">&lt;p&gt;This prompt builds the guided project setup experience for new institutional users. Read the full codebase before starting — particularly the existing node structure, the auth system, and how institution/project/cycle nodes are currently seeded in seedLFTI().&lt;/p&gt;
&lt;p&gt;The goal: a teacher or facilitator at a new school can go from first login to a working project skeleton in under 2 minutes. Everything inferrable is pre-populated. Everything non-essential has a sensible default. Details can be added later.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Design principles for this feature&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Speed over completeness.&lt;/strong&gt; The setup flow must be fast. A teacher has 5 minutes before a class. Pre-populate aggressively. Make every field optional except the bare minimum to create the structure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The right thing should be the obvious thing.&lt;/strong&gt; In Zambia and elsewhere, excellent facilitators may find the tech challenging. The UI must make correct process hard to avoid and the next step always clear.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Group contributions as the default.&lt;/strong&gt; The system nudges toward group work (4–6 students per group) rather than individual contributions. This reduces the approval bottleneck and matches the participatory methodology.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Approval protects without blocking.&lt;/strong&gt; Student content is visible within the project immediately but requires teacher/facilitator approval before publishing externally. This is the default (async). A live session mode (sync) is available as a toggle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nodes are still the underlying structure.&lt;/strong&gt; The setup wizard creates real nodes — institution, project, staff, class, cycle, phase nodes — using the existing API. The wizard is a friendly skin over node creation, not a separate system.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Institution landing page&lt;/h2&gt;
&lt;p&gt;When an institution_admin or facilitator logs in and their institution node exists but has no project nodes under it, the landing page (content area when the institution node is selected) shows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────┐
│                                                     │
│   Welcome to LFTI                                   │
│   [institution name]                                │
│                                                     │
│   ┌─────────────────────────────────────────────┐   │
│   │         + Start Your First Project          │   │
│   │         (large, accent colour, dominant)    │   │
│   └─────────────────────────────────────────────┘   │
│                                                     │
│   Complete your institution profile  →              │
│   (smaller, secondary, below the main button)       │
│                                                     │
└─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once at least one project exists, the institution landing page shows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Active projects as cards (title, status, date range, participant count)&lt;/li&gt;
&lt;li&gt;A smaller &lt;code&gt;+ New Project&lt;/code&gt; button in the top right of the projects section&lt;/li&gt;
&lt;li&gt;Creating a node of type &lt;code&gt;project&lt;/code&gt; under the institution node also triggers the setup wizard&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Project setup wizard&lt;/h2&gt;
&lt;p&gt;A full-screen overlay (same pattern as quick-capture but larger). Five steps, shown as a progress indicator at the top. Each step has a Back and Next button. Final step has a Launch Project button.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Progress indicator:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;① Project basics  ② Schedule  ③ Participants  ④ Format  ⑤ Review
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clicking a completed step navigates back to it. Incomplete future steps are greyed out.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Step 1 — Project basics&lt;/h3&gt;
&lt;p&gt;Fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Project name&lt;/strong&gt; (text, required) — pre-populated with “[Institution name] — LFTI [current year]”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Description&lt;/strong&gt; (textarea, optional) — placeholder: “What is this project about? Who is involved? You can add this later.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Country context&lt;/strong&gt; (auto-detected from institution node’s context tag — uk / nz / zambia / other) — shown as a read-only badge, editable if wrong&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partner institution&lt;/strong&gt; (optional) — search existing institutions by name. If selected, marks this as a paired project. Can be added later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pre-population logic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Institution name comes from the logged-in user’s institution_id → institution node title&lt;/li&gt;
&lt;li&gt;Year comes from current date&lt;/li&gt;
&lt;li&gt;Country context comes from institution node meta.context&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;Step 2 — Schedule&lt;/h3&gt;
&lt;p&gt;Fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Project format&lt;/strong&gt; (segmented control, required):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Intensive week&lt;/code&gt; — one continuous week&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Weekly sessions&lt;/code&gt; — one session per week over a half-term or term&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Custom&lt;/code&gt; — define your own structure&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start date&lt;/strong&gt; (date picker, required) — defaults to next Monday&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;End date&lt;/strong&gt; (date picker, required) — auto-calculated based on format:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Intensive week: start + 5 days&lt;/li&gt;
&lt;li&gt;Weekly sessions: start + 6 weeks&lt;/li&gt;
&lt;li&gt;Custom: user sets manually&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Workshop dates&lt;/strong&gt; (appears after start/end are set) — a simple list of specific dates within the range. Pre-populated based on format:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Intensive week: Mon–Fri of the start week&lt;/li&gt;
&lt;li&gt;Weekly sessions: same day each week for 6 weeks&lt;/li&gt;
&lt;li&gt;Custom: empty, user adds dates manually&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each date can have a label (e.g. “Day 1 — Past Gather”) — pre-populated with sensible defaults, editable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Academic calendar&lt;/strong&gt; (select, optional) — UK / NZ / Zambia / Custom. Auto-detected from country context. Used for display formatting of dates.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;Step 3 — Participants&lt;/h3&gt;
&lt;p&gt;Three sections, each collapsible:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Staff &amp;amp; facilitators:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add by name + email (they’ll get an invite — invite system is a placeholder for now, just store the email in the person node’s meta)&lt;/li&gt;
&lt;li&gt;Role: institution_admin / facilitator (select)&lt;/li&gt;
&lt;li&gt;Pre-populated with the logged-in user&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Classes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add class name (e.g. “Year 9 — 9A”, “Form 3 North”)&lt;/li&gt;
&lt;li&gt;Class teacher name + email (optional — can add later)&lt;/li&gt;
&lt;li&gt;Approximate student count (number input, optional) — used to suggest group sizes&lt;/li&gt;
&lt;li&gt;Multiple classes can be added with &lt;code&gt;+ Add another class&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Groups (within classes):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Auto-suggested based on student count: “Based on [n] students, we suggest [n/5 rounded up] groups of 4–5”&lt;/li&gt;
&lt;li&gt;Groups can be named or left as Group 1, Group 2 etc&lt;/li&gt;
&lt;li&gt;Students self-assign to groups within the app (organic — not set up by admin)&lt;/li&gt;
&lt;li&gt;Soft content limit per group: 5 contributions per tool phase (shown as a nudge, not a hard block)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Minimum viable:&lt;/strong&gt; Just the logged-in user as a participant is enough to proceed. Everything else can be added later.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Step 4 — Format&lt;/h3&gt;
&lt;p&gt;This step configures the cycle structure and approval settings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Movements to include&lt;/strong&gt; (multi-select, all selected by default):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;☑ Past&lt;/li&gt;
&lt;li&gt;☑ Situation&lt;/li&gt;
&lt;li&gt;☑ Futures&lt;/li&gt;
&lt;li&gt;☑ Whole (auto-includes, greyed out with tooltip: “The Whole cycle draws from all three movements”)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Approval mode:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Content approval

○ Standard (recommended)
  Student group content is visible within your project immediately.
  You approve before it&#39;s shared externally.
  Good for: most classroom situations, when you&#39;re also facilitating.

○ Live session mode
  You see uploads in real time and approve as they come in.
  Good for: whiteboard sessions with a co-facilitator.
  
  You can switch between modes at any time during the project.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Group contribution soft limit:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Suggested contributions per group per phase: [5] (editable number)
Groups will see a nudge when they reach this limit.
They can add more, but are encouraged to prioritise first.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;International exchange:&lt;/strong&gt;
If a partner institution was selected in Step 1, show:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;☑ Enable story interchange with [partner institution name]
  Students will be able to see and respond to each other&#39;s 
  approved Present artefacts.
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3&gt;Step 5 — Review&lt;/h3&gt;
&lt;p&gt;A clean summary of everything configured:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PROJECT
  Name: [name]
  Institution: [institution]
  Partner: [partner or &amp;quot;standalone&amp;quot;]
  
SCHEDULE  
  Format: [format]
  Dates: [start] → [end]
  Sessions: [n] workshop dates

PARTICIPANTS
  Staff: [n]
  Classes: [n] ([total students approx])
  Groups: [n groups suggested]

STRUCTURE
  Movements: Past, Situation, Futures, Whole
  Phases per movement: Gather → Collate → Present
  Total cycle nodes: 12

APPROVAL
  Mode: Standard / Live session
  Group limit: [n] contributions per phase

[ Back ]                    [ Launch Project → ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Launch Project&lt;/code&gt; button:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creates all nodes (see Node generation below)&lt;/li&gt;
&lt;li&gt;Shows a brief “Building your project…” animation (just a spinner with the text)&lt;/li&gt;
&lt;li&gt;Navigates to the new project node on completion&lt;/li&gt;
&lt;li&gt;The project node’s content area shows the project dashboard (see below)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Node generation on Launch&lt;/h2&gt;
&lt;p&gt;The wizard creates the following nodes via the existing &lt;code&gt;PUT /api/nodes/:id&lt;/code&gt; endpoint:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Project node:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;id&amp;quot;: &amp;quot;proj_[timestamp]&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;project&amp;quot;,
  &amp;quot;title&amp;quot;: &amp;quot;[project name]&amp;quot;,
  &amp;quot;parent_ids&amp;quot;: [&amp;quot;[institution_id]&amp;quot;],
  &amp;quot;relations&amp;quot;: [
    { &amp;quot;type&amp;quot;: &amp;quot;hosts&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;[institution_id]&amp;quot; }
  ],
  &amp;quot;meta&amp;quot;: {
    &amp;quot;status&amp;quot;: &amp;quot;active&amp;quot;,
    &amp;quot;format&amp;quot;: &amp;quot;intensive_week|weekly|custom&amp;quot;,
    &amp;quot;start_date&amp;quot;: &amp;quot;ISO date&amp;quot;,
    &amp;quot;end_date&amp;quot;: &amp;quot;ISO date&amp;quot;,
    &amp;quot;workshop_dates&amp;quot;: [&amp;quot;ISO date&amp;quot;, ...],
    &amp;quot;academic_calendar&amp;quot;: &amp;quot;uk|nz|zambia|custom&amp;quot;,
    &amp;quot;approval_mode&amp;quot;: &amp;quot;standard|live&amp;quot;,
    &amp;quot;group_limit&amp;quot;: 5,
    &amp;quot;country_context&amp;quot;: &amp;quot;uk|nz|zambia|other&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Four movement nodes&lt;/strong&gt; (Past, Situation, Futures, Whole):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;id&amp;quot;: &amp;quot;mov_[proj]_past&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;cycle&amp;quot;,
  &amp;quot;title&amp;quot;: &amp;quot;Past&amp;quot;,
  &amp;quot;parent_ids&amp;quot;: [&amp;quot;proj_[timestamp]&amp;quot;],
  &amp;quot;relations&amp;quot;: [
    { &amp;quot;type&amp;quot;: &amp;quot;contains&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;phase_[proj]_past_gather&amp;quot; },
    { &amp;quot;type&amp;quot;: &amp;quot;sequence&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;mov_[proj]_situation&amp;quot; },
    { &amp;quot;type&amp;quot;: &amp;quot;references&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;ref_g_phase&amp;quot; }
  ],
  &amp;quot;meta&amp;quot;: {
    &amp;quot;movement&amp;quot;: &amp;quot;past&amp;quot;,
    &amp;quot;status&amp;quot;: &amp;quot;not_started&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Twelve phase nodes&lt;/strong&gt; (3 phases × 4 movements):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;id&amp;quot;: &amp;quot;phase_[proj]_past_gather&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;session&amp;quot;,
  &amp;quot;title&amp;quot;: &amp;quot;Past — Gather&amp;quot;,
  &amp;quot;parent_ids&amp;quot;: [&amp;quot;mov_[proj]_past&amp;quot;],
  &amp;quot;relations&amp;quot;: [
    { &amp;quot;type&amp;quot;: &amp;quot;sequence&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;phase_[proj]_past_collate&amp;quot; },
    { &amp;quot;type&amp;quot;: &amp;quot;references&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;ref_g_phase&amp;quot; }
  ],
  &amp;quot;meta&amp;quot;: {
    &amp;quot;movement&amp;quot;: &amp;quot;past&amp;quot;,
    &amp;quot;phase&amp;quot;: &amp;quot;gather&amp;quot;,
    &amp;quot;status&amp;quot;: &amp;quot;not_started&amp;quot;,
    &amp;quot;approval_mode&amp;quot;: &amp;quot;standard&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The feeds relations for Whole cycle:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{ &amp;quot;type&amp;quot;: &amp;quot;feeds&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;phase_[proj]_whole_gather&amp;quot;, &amp;quot;from&amp;quot;: &amp;quot;phase_[proj]_past_present&amp;quot; }
{ &amp;quot;type&amp;quot;: &amp;quot;feeds&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;phase_[proj]_whole_gather&amp;quot;, &amp;quot;from&amp;quot;: &amp;quot;phase_[proj]_situation_present&amp;quot; }
{ &amp;quot;type&amp;quot;: &amp;quot;feeds&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;phase_[proj]_whole_gather&amp;quot;, &amp;quot;from&amp;quot;: &amp;quot;phase_[proj]_futures_present&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Person nodes&lt;/strong&gt; for staff added in Step 3:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;id&amp;quot;: &amp;quot;person_[timestamp]&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;person&amp;quot;,
  &amp;quot;title&amp;quot;: &amp;quot;[name]&amp;quot;,
  &amp;quot;parent_ids&amp;quot;: [&amp;quot;proj_[timestamp]&amp;quot;],
  &amp;quot;relations&amp;quot;: [{ &amp;quot;type&amp;quot;: &amp;quot;involves&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;proj_[timestamp]&amp;quot; }],
  &amp;quot;meta&amp;quot;: {
    &amp;quot;role&amp;quot;: &amp;quot;facilitator|institution_admin&amp;quot;,
    &amp;quot;email&amp;quot;: &amp;quot;[email]&amp;quot;,
    &amp;quot;invite_status&amp;quot;: &amp;quot;pending&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Class nodes:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;id&amp;quot;: &amp;quot;class_[timestamp]&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;session&amp;quot;,
  &amp;quot;title&amp;quot;: &amp;quot;[class name]&amp;quot;,
  &amp;quot;parent_ids&amp;quot;: [&amp;quot;proj_[timestamp]&amp;quot;],
  &amp;quot;relations&amp;quot;: [{ &amp;quot;type&amp;quot;: &amp;quot;involves&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;proj_[timestamp]&amp;quot; }],
  &amp;quot;meta&amp;quot;: {
    &amp;quot;student_count&amp;quot;: n,
    &amp;quot;suggested_groups&amp;quot;: n,
    &amp;quot;teacher_email&amp;quot;: &amp;quot;[email]&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Project dashboard (post-launch view)&lt;/h2&gt;
&lt;p&gt;When a project node is selected, its content section shows a project dashboard instead of the standard parents/content/children layout.&lt;/p&gt;
&lt;p&gt;The dashboard has two views, toggled by a small tab:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Overview tab (default):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Project name]                    [Standard mode ▾]  [⚙ Settings]

PROGRESS
Past        [Gather ●●●○○] [Collate ○○○○○] [Present ○○○○○]
Situation   [Gather ○○○○○] [Collate ○○○○○] [Present ○○○○○]  
Futures     [Gather ○○○○○] [Collate ○○○○○] [Present ○○○○○]
Whole       [Gather ○○○○○] [Collate ○○○○○] [Present ○○○○○]

● = contributions uploaded  ○ = empty

NEEDS ATTENTION
  ▶ 3 group contributions awaiting your approval   [Review →]
  ▶ Situation — Gather has no tool selected yet    [Choose tool →]

PARTICIPANTS
  2 staff  ·  1 class  ·  6 groups  ·  ~30 students
  [Manage →]

UPCOMING
  Day 2 — Past Collate    Tomorrow
  Day 3 — Past Present    Thursday
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Approval tab&lt;/strong&gt; (shows when approval_mode is standard):&lt;/p&gt;
&lt;p&gt;A list of pending contributions — group name, tool used, phase, timestamp. Each has an Approve and Flag button. Flagged contributions go back to the group with a note.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Live session mode toggle:&lt;/strong&gt;
When switched to live mode, the approval tab becomes a real-time feed — contributions appear as they’re uploaded. A large Approve button dominates. Designed for a facilitator watching a whiteboard.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Navigation changes&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;In the tree panel:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Project nodes show a status indicator dot (green = active, grey = not started, amber = needs attention)&lt;/li&gt;
&lt;li&gt;Phase nodes show a progress indicator (e.g. “3 contributions” or “approved”)&lt;/li&gt;
&lt;li&gt;Clicking a phase node navigates to it AND highlights the relevant reference tool nodes in a subtle way (“these tools are available for this phase”)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;New project from tree:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Right-clicking an institution node (or long-press on mobile) shows a context menu: &lt;code&gt;+ New Project&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;This triggers the same wizard&lt;/li&gt;
&lt;li&gt;Creating a node of type &lt;code&gt;project&lt;/code&gt; manually also prompts: “Would you like to use the project setup wizard?” Yes launches wizard pre-filled with the node’s title. No creates a bare node.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;What does NOT change&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Existing node structure — unchanged&lt;/li&gt;
&lt;li&gt;Auth system — unchanged&lt;/li&gt;
&lt;li&gt;Reference instance — unchanged&lt;/li&gt;
&lt;li&gt;Tree / position / graph navigation modes — unchanged&lt;/li&gt;
&lt;li&gt;Image maps, temporal nav, quick capture — unchanged&lt;/li&gt;
&lt;li&gt;The standard content view (parents / this node / children) — still available for all nodes including project nodes, accessible via a small “node view” link in the project dashboard&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;File structure changes&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;/
├── api/
│   └── projects.js     (new — project creation endpoint that generates full skeleton)
├── lfti-spine.html     (modified — wizard UI, dashboard UI, navigation changes)
└── server.js           (modified — mount projects router)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The project creation logic (generating all 12+ nodes in one transaction) lives in &lt;code&gt;api/projects.js&lt;/code&gt; rather than the frontend, so the skeleton is generated atomically server-side. The frontend sends one POST with the wizard data; the server creates all nodes and returns the project id.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /api/projects
  body: { name, institution_id, format, start_date, end_date, 
          workshop_dates, movements, approval_mode, group_limit,
          staff, classes, partner_institution_id }
  response: { project_id, nodes_created: n }
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;When you’re done&lt;/h2&gt;
&lt;p&gt;Test these five things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Log in as &lt;code&gt;ukadmin@lfti.dev&lt;/code&gt;. Select the UK Schools institution node. See the dominant “Start Your First Project” button. Click it. The wizard opens.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Complete the wizard with minimal input (just accept all defaults, click Next through each step). Click Launch Project. A project node appears in the tree under UK Schools with 4 movement nodes and 12 phase nodes as children.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The project dashboard loads showing the progress grid (all empty), no needs-attention items, and the participant count.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Log in as &lt;code&gt;student1@lfti.dev&lt;/code&gt; in another browser. Navigate to the new project. Can see the project and its cycle structure. Cannot see the approval tab. Cannot delete anything.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Log in as &lt;code&gt;facilitator@lfti.dev&lt;/code&gt;. Navigate to a phase node (e.g. Past — Gather). See a nudge toward the reference tool library for that phase (“Browse Gather tools →” linking to the reference Gather Phase node).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  <entry>
    <title>Reference instance seeding</title>
    <link href="https://themetalevel.org/notes/lfti-reference-seed/"/>
    <updated>2026-05-21T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/lfti-reference-seed/</id>
    <summary>This prompt depends on the graph migration already being complete and working. Before starting, confirm that: - GET /api/nodes returns nodes with relations[] arrays - The…</summary>
    <content type="html">&lt;p&gt;This prompt depends on the graph migration already being complete and working. Before starting, confirm that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /api/nodes&lt;/code&gt; returns nodes with &lt;code&gt;relations[]&lt;/code&gt; arrays&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;relations_index&lt;/code&gt; table exists in the database&lt;/li&gt;
&lt;li&gt;The left panel has tree / position / graph mode tabs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If any of those are not working, stop and complete the graph migration first.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;What this prompt does&lt;/h2&gt;
&lt;p&gt;Seeds the LFTI &lt;strong&gt;reference instance&lt;/strong&gt; — the canonical methodology layer that defines what each tool, principle, and phase means. This is not project data. It is the living documentation of the participatory methodology that LFTI uses and that partner institutions can see and learn from.&lt;/p&gt;
&lt;p&gt;Read &lt;code&gt;codeReference/PLA_TOOLS_REFERENCE.md&lt;/code&gt; fully before writing a single line of seed code. That document is the source of truth. Everything you build here comes from it.&lt;/p&gt;
&lt;p&gt;Also re-read the existing &lt;code&gt;seedLFTI()&lt;/code&gt; function in &lt;code&gt;lfti-spine.html&lt;/code&gt; to understand the existing node structure before adding to it. You are extending the seed, not replacing it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Structure to build&lt;/h2&gt;
&lt;p&gt;The reference instance sits as a parallel branch under the root LFTI node, connected by a &lt;code&gt;contains&lt;/code&gt; relation. It does not replace or reorganise the existing node tree.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LFTI (root, already exists)
  ├── [existing nodes — unchanged]
  └── Reference Instance              ← new, add here
        ├── Principles &amp;amp; Ethos        ← methodology layer
        │     ├── [one node per principle]
        ├── Gather Phase              ← reference phase node
        │     ├── [one node per tool]
        │     │     └── [block nodes for variants/steps where specified]
        ├── Collate Phase
        │     ├── Collaborative Prioritisation  ← tool category node
        │     │     └── [tool nodes]
        │     ├── Diagramming                   ← tool category node
        │     │     └── [tool nodes]
        │     └── [remaining collate tools]
        ├── Present Phase
        │     └── [tool nodes]
        └── Cross-cutting Tools
              └── [tool nodes]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Node construction rules&lt;/h2&gt;
&lt;p&gt;Read &lt;code&gt;codeReference/PLA_TOOLS_REFERENCE.md&lt;/code&gt; seeding instructions section (at the bottom of that document). They are authoritative. Summary:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tool nodes:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;type&amp;quot;: &amp;quot;tool&amp;quot;,
  &amp;quot;meta&amp;quot;: {
    &amp;quot;_level&amp;quot;: &amp;quot;reference&amp;quot;,
    &amp;quot;_visibility&amp;quot;: &amp;quot;partners&amp;quot;,
    &amp;quot;phase&amp;quot;: &amp;quot;gather&amp;quot;           // or collate / present / cross-cutting
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Principle nodes:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;type&amp;quot;: &amp;quot;note&amp;quot;,
  &amp;quot;meta&amp;quot;: {
    &amp;quot;_level&amp;quot;: &amp;quot;reference&amp;quot;,
    &amp;quot;_visibility&amp;quot;: &amp;quot;partners&amp;quot;,
    &amp;quot;category&amp;quot;: &amp;quot;principle&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Placeholder nodes&lt;/strong&gt; (Synthesis canvas):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;meta&amp;quot;: {
    &amp;quot;_level&amp;quot;: &amp;quot;reference&amp;quot;,
    &amp;quot;_placeholder&amp;quot;: true,
    &amp;quot;_placeholder_note&amp;quot;: &amp;quot;Collaborative canvas deferred. Node holds shape.&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Body Map specifically:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;meta&amp;quot;: {
    &amp;quot;_level&amp;quot;: &amp;quot;reference&amp;quot;,
    &amp;quot;_facilitation_owner&amp;quot;: &amp;quot;Kamoto/Mary Manzole&amp;quot;,
    &amp;quot;_status&amp;quot;: &amp;quot;protocol_pending&amp;quot;,
    &amp;quot;_status_note&amp;quot;: &amp;quot;Full facilitation protocol to be documented with Mary Manzole. Do not use without that protocol.&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Node bodies:&lt;/strong&gt; Copy the description and key content from &lt;code&gt;PLA_TOOLS_REFERENCE.md&lt;/code&gt; directly into node bodies. Do not summarise or paraphrase — these are reference nodes and their body text is their value. Facilitation steps go in the body as prose, not as child nodes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Node titles:&lt;/strong&gt; Use the &lt;code&gt;###&lt;/code&gt; heading text from the reference document exactly, prefixed with the phase abbreviation where helpful for disambiguation. E.g. “Gather — Transect Walk”, “Collate — Matrix Ranking”.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Relations to add&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;From Reference Instance node to phase nodes:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{ &amp;quot;type&amp;quot;: &amp;quot;contains&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;ref_gather_phase&amp;quot; }
{ &amp;quot;type&amp;quot;: &amp;quot;contains&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;ref_collate_phase&amp;quot; }
{ &amp;quot;type&amp;quot;: &amp;quot;contains&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;ref_present_phase&amp;quot; }
{ &amp;quot;type&amp;quot;: &amp;quot;contains&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;ref_principles&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;From LFTI root to Reference Instance:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{ &amp;quot;type&amp;quot;: &amp;quot;contains&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;ref_instance&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;From tool nodes to existing institution nodes&lt;/strong&gt; (provenance):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Body Map → &lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;involves&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;kamoto&amp;quot; }&lt;/code&gt; (Kamoto node already exists in seed)&lt;/li&gt;
&lt;li&gt;Pre-perceptions → &lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;involves&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;glm&amp;quot; }&lt;/code&gt; (GLM node already exists)&lt;/li&gt;
&lt;li&gt;PPP tools generally → &lt;code&gt;{ &amp;quot;type&amp;quot;: &amp;quot;involves&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;kamoto&amp;quot; }&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;From existing cycle nodes to reference phase nodes&lt;/strong&gt; (instance references methodology):
For each of the twelve cycle nodes already in the seed (Past→Gather, Past→Collate, etc.):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{ &amp;quot;type&amp;quot;: &amp;quot;references&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;ref_gather_phase&amp;quot; }  // or collate / present
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;From Pre-perceptions tool node to Whole cycle Gather node:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{ &amp;quot;type&amp;quot;: &amp;quot;feeds&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;cycle_whole_gather&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This represents that the second pre-perceptions instance runs in the Whole cycle’s Gather phase.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;IDs&lt;/h2&gt;
&lt;p&gt;Use a consistent prefix scheme:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ref_&lt;/code&gt; — reference instance root and phase nodes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ref_p_&lt;/code&gt; — principle nodes (e.g. &lt;code&gt;ref_p_handing_over_stick&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ref_g_&lt;/code&gt; — gather tool nodes (e.g. &lt;code&gt;ref_g_transect_walk&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ref_g_b_&lt;/code&gt; — gather tool block/variant nodes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ref_c_&lt;/code&gt; — collate tool nodes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ref_c_cat_&lt;/code&gt; — collate tool category nodes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ref_pr_&lt;/code&gt; — present tool nodes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ref_x_&lt;/code&gt; — cross-cutting tool nodes&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Where to add the seed code&lt;/h2&gt;
&lt;p&gt;Add a new function &lt;code&gt;seedReferenceInstance()&lt;/code&gt; in &lt;code&gt;lfti-spine.html&lt;/code&gt; immediately after the existing &lt;code&gt;seedLFTI()&lt;/code&gt; function. Call it from the boot sequence after &lt;code&gt;seedLFTI()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;seedLFTI();
seedReferenceInstance();
loadDB();
saveDB();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;seedReferenceInstance()&lt;/code&gt; should check if the reference instance root node already exists before seeding, to make the boot sequence safe to run multiple times:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function seedReferenceInstance() {
  if (state.nodes[&#39;ref_instance&#39;]) return; // already seeded
  // ... seed code
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Visual treatment in the UI&lt;/h2&gt;
&lt;p&gt;Reference instance nodes already get visual treatment from the graph migration (&lt;code&gt;ref&lt;/code&gt; badge, dimmed title, read-only styled inputs). Confirm this is working correctly for the new nodes.&lt;/p&gt;
&lt;p&gt;In the left panel &lt;strong&gt;position mode&lt;/strong&gt;, reference nodes should appear when the matching movement/phase filters are active — so when a facilitator is looking at “Gather phase” in position mode, they see both the real project’s Gather nodes AND the reference Gather tool nodes together. This is intentional: the reference is not hidden away, it is visible alongside the live work as a resource.&lt;/p&gt;
&lt;p&gt;To enable this, reference tool nodes need &lt;code&gt;meta.phase&lt;/code&gt; set to their phase value (already specified above). Position mode filtering should already pick this up if it filters on &lt;code&gt;meta.phase&lt;/code&gt; — confirm this works and adjust the position mode filter logic if needed.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Expanded node set for position mode&lt;/h2&gt;
&lt;p&gt;Now that reference tools are in the system, extend the position mode &lt;strong&gt;context filter&lt;/strong&gt; to include:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ UK ] [ NZ ] [ Zambia ] [ cross-cohort ] [ reference ] [ all ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;reference&lt;/code&gt; context filter shows only &lt;code&gt;_level: &amp;quot;reference&amp;quot;&lt;/code&gt; nodes. This gives facilitators a clean way to browse the tool library while in position mode — “show me all Gather tools” by selecting phase:gather + context:reference.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;What does NOT change&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Existing seed nodes — unchanged&lt;/li&gt;
&lt;li&gt;Existing API endpoints — unchanged&lt;/li&gt;
&lt;li&gt;Existing tree view — unchanged (reference nodes appear in tree under their parent)&lt;/li&gt;
&lt;li&gt;Temporal navigation — unchanged&lt;/li&gt;
&lt;li&gt;Image attachments — unchanged&lt;/li&gt;
&lt;li&gt;Footer bar — unchanged&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;When you’re done&lt;/h2&gt;
&lt;p&gt;Test these five things in order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Boot the server fresh (or clear and reseed). &lt;code&gt;GET /api/nodes&lt;/code&gt; returns reference instance nodes with correct &lt;code&gt;meta._level: &amp;quot;reference&amp;quot;&lt;/code&gt; and &lt;code&gt;relations[]&lt;/code&gt; arrays including &lt;code&gt;involves&lt;/code&gt; relations to Kamoto and GLM where specified.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the left panel tree view, navigate to the Reference Instance node. Expand it. The full hierarchy is visible: Principles &amp;amp; Ethos, Gather Phase, Collate Phase, Present Phase, Cross-cutting Tools, each with their child tool nodes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the Body Map node. Confirm: &lt;code&gt;ref&lt;/code&gt; badge visible, inputs styled read-only, &lt;code&gt;meta._status: &amp;quot;protocol_pending&amp;quot;&lt;/code&gt; visible somewhere in the content section (add a small status indicator if not already present for &lt;code&gt;_status&lt;/code&gt; meta values).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switch to &lt;strong&gt;position mode&lt;/strong&gt;. Select phase: Gather, context: reference. The Gather tool nodes appear as cards — Observation, Semi-structured Interview, Transect Walk, Body Map, Photo Walk, Story Circle, River of Life, Peer Interview, Learning Journal, Timeline, Focus Group, Pre-perceptions. No live project nodes appear.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select phase: Gather, context: all. Both reference tool nodes AND live project Gather nodes appear together. The reference nodes have the &lt;code&gt;ref&lt;/code&gt; badge; the live nodes do not.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  <entry>
    <title>Tool instance foundation</title>
    <link href="https://themetalevel.org/notes/lfti-tool-instance/"/>
    <updated>2026-05-21T00:00:00.000Z</updated>
    <id>https://themetalevel.org/notes/lfti-tool-instance/</id>
    <summary>This prompt builds the structural foundation for tool instances — the live, project-specific running version of a reference tool.</summary>
    <content type="html">&lt;p&gt;This prompt builds the structural foundation for tool instances — the live, project-specific
running version of a reference tool. Read the full codebase before starting, particularly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The reference tool nodes and their meta fields (phase, format, location, modality etc)&lt;/li&gt;
&lt;li&gt;The phase node structure (meta.phase, meta.movement, meta.status, meta.selected_tools)&lt;/li&gt;
&lt;li&gt;The existing contribution/artefact flow from Phase 3&lt;/li&gt;
&lt;li&gt;api/projects.js and the node creation patterns established there&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This prompt has four distinct pieces. Build and verify each before starting the next.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;PIECE 1 — Filter option extensibility&lt;/h2&gt;
&lt;p&gt;Currently tool filter properties (format, location, modality, duration, tech_level) are
hardcoded strings in the tool browser UI. They need to become a database-backed extensible
list so new options can be added without code changes.&lt;/p&gt;
&lt;h3&gt;New database table&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE TABLE IF NOT EXISTS filter_options (
  id          TEXT PRIMARY KEY,
  filter_type TEXT NOT NULL,    -- &amp;quot;format&amp;quot; | &amp;quot;location&amp;quot; | &amp;quot;modality&amp;quot; | &amp;quot;duration&amp;quot; | &amp;quot;tech_level&amp;quot;
  value       TEXT NOT NULL,    -- &amp;quot;indoors&amp;quot; | &amp;quot;outdoors&amp;quot; | &amp;quot;playing fields&amp;quot; etc
  label       TEXT NOT NULL,    -- display label, may differ from value
  created_by  TEXT,             -- user id who added it, null for seeded options
  created_at  TEXT NOT NULL,
  UNIQUE(filter_type, value)
);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Seed the initial options&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const initialOptions = [
  // format
  { filter_type: &#39;format&#39;, value: &#39;individual&#39;, label: &#39;Individual&#39; },
  { filter_type: &#39;format&#39;, value: &#39;group&#39;, label: &#39;Group&#39; },
  // location
  { filter_type: &#39;location&#39;, value: &#39;indoors&#39;, label: &#39;Indoors&#39; },
  { filter_type: &#39;location&#39;, value: &#39;outdoors&#39;, label: &#39;Outdoors&#39; },
  // modality
  { filter_type: &#39;modality&#39;, value: &#39;sync&#39;, label: &#39;Synchronous&#39; },
  { filter_type: &#39;modality&#39;, value: &#39;async&#39;, label: &#39;Asynchronous&#39; },
  // duration
  { filter_type: &#39;duration&#39;, value: &#39;&amp;lt;30min&#39;, label: &#39;Under 30 min&#39; },
  { filter_type: &#39;duration&#39;, value: &#39;30-60min&#39;, label: &#39;30–60 min&#39; },
  { filter_type: &#39;duration&#39;, value: &#39;60min+&#39;, label: &#39;60 min+&#39; },
  // tech_level
  { filter_type: &#39;tech_level&#39;, value: &#39;low&#39;, label: &#39;Low tech&#39; },
  { filter_type: &#39;tech_level&#39;, value: &#39;high&#39;, label: &#39;High tech&#39; },
];
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;New API endpoints&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;GET /api/filter-options
  Returns all filter options grouped by filter_type
  { format: [...], location: [...], modality: [...], ... }
  Auth: any authenticated user

POST /api/filter-options
  Body: { filter_type, value, label }
  Creates a new filter option if the (filter_type, value) pair doesn&#39;t exist
  Auth: institution_admin+ only
  Returns: the created option
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Frontend changes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;On boot, fetch &lt;code&gt;/api/filter-options&lt;/code&gt; and store in &lt;code&gt;state.filterOptions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Replace all hardcoded filter pill arrays in the tool browser with values from
&lt;code&gt;state.filterOptions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In the tool browser filter UI, add a small &lt;code&gt;+ add filter option&lt;/code&gt; link at the end
of each filter group (visible to institution_admin+ only). Clicking opens a tiny
inline form: label input + POST /api/filter-options. On success, refreshes
state.filterOptions and re-renders the filter pills.&lt;/li&gt;
&lt;li&gt;New options are immediately available when editing any tool node’s filter meta fields&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verify piece 1&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;GET /api/filter-options returns all seeded options grouped correctly&lt;/li&gt;
&lt;li&gt;Tool browser filter pills render from the API, not hardcoded&lt;/li&gt;
&lt;li&gt;As institution_admin, add “Playing fields” to location filter type&lt;/li&gt;
&lt;li&gt;“Playing fields” appears as a filter pill in the tool browser immediately&lt;/li&gt;
&lt;li&gt;As student, the “+ add filter option” link is not visible&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;PIECE 2 — Tool instance node&lt;/h2&gt;
&lt;p&gt;When a facilitator clicks “Start this phase →” on a phase node (after selecting tools),
the system currently sets meta.selected_tools on the phase node. Replace this behaviour:
instead of storing selected_tools on the phase node, create a tool instance node as a
child of the phase node for each selected tool.&lt;/p&gt;
&lt;h3&gt;Tool instance node structure&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;id&amp;quot;: &amp;quot;ti_[timestamp]_[random]&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;tool_instance&amp;quot;,
  &amp;quot;title&amp;quot;: &amp;quot;[Tool name] — [Phase] — [Date]&amp;quot;,
  &amp;quot;parent_id&amp;quot;: &amp;quot;[phase_node_id]&amp;quot;,
  &amp;quot;relations&amp;quot;: [
    { &amp;quot;type&amp;quot;: &amp;quot;references&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;[ref_tool_node_id]&amp;quot; },
    { &amp;quot;type&amp;quot;: &amp;quot;contains&amp;quot;,   &amp;quot;target&amp;quot;: &amp;quot;[group_instance_id]&amp;quot; }
  ],
  &amp;quot;meta&amp;quot;: {
    &amp;quot;phase&amp;quot;: &amp;quot;gather&amp;quot;,
    &amp;quot;movement&amp;quot;: &amp;quot;past&amp;quot;,
    &amp;quot;ref_tool_id&amp;quot;: &amp;quot;[ref_tool_node_id]&amp;quot;,
    &amp;quot;status&amp;quot;: &amp;quot;preparing&amp;quot;,
    &amp;quot;modality&amp;quot;: &amp;quot;digital&amp;quot;,
    &amp;quot;created_by&amp;quot;: &amp;quot;[user_id]&amp;quot;,
    &amp;quot;created_at&amp;quot;: &amp;quot;ISO&amp;quot;,
    &amp;quot;started_at&amp;quot;: null,
    &amp;quot;completed_at&amp;quot;: null,
    &amp;quot;steps&amp;quot;: [
      {
        &amp;quot;id&amp;quot;: &amp;quot;step_1&amp;quot;,
        &amp;quot;title&amp;quot;: &amp;quot;Step title&amp;quot;,
        &amp;quot;body&amp;quot;: &amp;quot;Step instructions&amp;quot;,
        &amp;quot;order&amp;quot;: 1,
        &amp;quot;capture_inline&amp;quot;: false
      }
    ],
    &amp;quot;local_variations&amp;quot;: [],
    &amp;quot;group_limit&amp;quot;: 5
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Steps&lt;/strong&gt; are copied from the reference tool node’s body at instance creation time,
parsed into discrete steps. The reference tool body uses a simple convention:
numbered steps separated by newlines. Parse these into the steps array.
If the reference tool body has no numbered steps, create one default step:
&lt;code&gt;{ title: &amp;quot;Run the activity&amp;quot;, body: &amp;quot;[full tool body text]&amp;quot;, order: 1 }&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;local_variations&lt;/strong&gt; is an empty array at creation. When a facilitator edits a step
(title or body) before Start is pressed, record the original and changed values here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{ &amp;quot;step_id&amp;quot;: &amp;quot;step_1&amp;quot;, &amp;quot;field&amp;quot;: &amp;quot;body&amp;quot;, &amp;quot;original&amp;quot;: &amp;quot;...&amp;quot;, &amp;quot;modified&amp;quot;: &amp;quot;...&amp;quot;, &amp;quot;modified_at&amp;quot;: &amp;quot;ISO&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the variation tracking mechanism for F17.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On creation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copy meta.phase and meta.movement from the parent phase node&lt;/li&gt;
&lt;li&gt;Copy meta.group_limit from the project node (walk up parent chain to find it)&lt;/li&gt;
&lt;li&gt;Fetch reference tool node to get steps and filter meta&lt;/li&gt;
&lt;li&gt;Set status to “preparing”&lt;/li&gt;
&lt;li&gt;Update parent phase node: remove meta.selected_tools (no longer needed),
set meta.status = “active”&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;New API endpoint&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;POST /api/tool-instances
  Body: { phase_node_id, ref_tool_ids: [&amp;quot;id1&amp;quot;, &amp;quot;id2&amp;quot;] }
  Creates one tool_instance node per ref_tool_id as child of phase_node_id
  Returns: { tool_instance_ids: [&amp;quot;ti_...&amp;quot;, &amp;quot;ti_...&amp;quot;] }
  Auth: facilitator+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Call this endpoint from the “Start this phase →” button instead of the current
meta.selected_tools approach.&lt;/p&gt;
&lt;h3&gt;Verify piece 2&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Select two tools on Past — Gather phase node, click “Start this phase →”&lt;/li&gt;
&lt;li&gt;Two tool_instance nodes appear as children of Past — Gather in the tree&lt;/li&gt;
&lt;li&gt;Each tool_instance node has correct meta: phase, movement, ref_tool_id, status: preparing&lt;/li&gt;
&lt;li&gt;Each has steps array populated from the reference tool body&lt;/li&gt;
&lt;li&gt;relations[] contains a references relation pointing to the correct ref tool node&lt;/li&gt;
&lt;li&gt;Phase node meta.status is now “active”, meta.selected_tools is gone&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;PIECE 3 — Group instance nodes&lt;/h2&gt;
&lt;p&gt;When a tool instance is created, generate a default set of group instance nodes as
children. The number of groups comes from the class node’s meta.suggested_groups
(set during project wizard). If no class is associated or suggested_groups is not set,
default to 3 groups.&lt;/p&gt;
&lt;h3&gt;Group instance node structure&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;id&amp;quot;: &amp;quot;gi_[timestamp]_[random]&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;group_instance&amp;quot;,
  &amp;quot;title&amp;quot;: &amp;quot;Group [n]&amp;quot;,
  &amp;quot;parent_id&amp;quot;: &amp;quot;[tool_instance_id]&amp;quot;,
  &amp;quot;relations&amp;quot;: [
    { &amp;quot;type&amp;quot;: &amp;quot;involves&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;[tool_instance_id]&amp;quot; }
  ],
  &amp;quot;meta&amp;quot;: {
    &amp;quot;tool_instance_id&amp;quot;: &amp;quot;[tool_instance_id]&amp;quot;,
    &amp;quot;group_number&amp;quot;: 1,
    &amp;quot;modality&amp;quot;: &amp;quot;digital&amp;quot;,
    &amp;quot;status&amp;quot;: &amp;quot;not_started&amp;quot;,
    &amp;quot;members&amp;quot;: [
      {
        &amp;quot;name&amp;quot;: &amp;quot;&amp;quot;,
        &amp;quot;role&amp;quot;: &amp;quot;&amp;quot;,
        &amp;quot;person_node_id&amp;quot;: null
      }
    ],
    &amp;quot;step_trace&amp;quot;: [],
    &amp;quot;submitted_at&amp;quot;: null,
    &amp;quot;uploaded_by&amp;quot;: null,
    &amp;quot;on_behalf_of&amp;quot;: null
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;members&lt;/strong&gt; array: starts empty (or with blank slots matching the reference tool’s
suggested group size if that field exists on the ref tool node meta).
Each member slot has name (free text), role (free text), and optionally a
person_node_id if matched to a roster entry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;step_trace&lt;/strong&gt; records timestamps as the group progresses through steps:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;[
  { &amp;quot;step_id&amp;quot;: &amp;quot;step_1&amp;quot;, &amp;quot;entered_at&amp;quot;: &amp;quot;ISO&amp;quot;, &amp;quot;exited_at&amp;quot;: &amp;quot;ISO&amp;quot; },
  { &amp;quot;step_id&amp;quot;: &amp;quot;step_2&amp;quot;, &amp;quot;entered_at&amp;quot;: &amp;quot;ISO&amp;quot;, &amp;quot;exited_at&amp;quot;: null }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the activity trace for the facilitator view (F17 basis).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;modality&lt;/strong&gt; defaults to “digital”. Can be changed to “paper” by the facilitator
in the tool instance view before Start is pressed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;on_behalf_of / uploaded_by&lt;/strong&gt;: for proxy uploads (F16) — when a facilitator uploads
content for a paper group, set uploaded_by to the facilitator’s user id and
on_behalf_of to the group_instance_id.&lt;/p&gt;
&lt;h3&gt;Generate group instances&lt;/h3&gt;
&lt;p&gt;Add group instance creation to &lt;code&gt;POST /api/tool-instances&lt;/code&gt;:
After creating the tool_instance node, create N group_instance child nodes.
N = class.meta.suggested_groups or 3 if not available.
Return group_instance_ids in the response.&lt;/p&gt;
&lt;h3&gt;Verify piece 3&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;After “Start this phase →”, expand a tool_instance node in the tree&lt;/li&gt;
&lt;li&gt;See N group_instance child nodes (matching suggested_groups or 3 default)&lt;/li&gt;
&lt;li&gt;Each group_instance has correct meta: tool_instance_id, group_number,
modality: digital, status: not_started, empty members array&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;PIECE 4 — Tool instance view and group management&lt;/h2&gt;
&lt;p&gt;When a node of type &lt;code&gt;tool_instance&lt;/code&gt; is selected, render a dedicated view instead of
the standard parents/content/children layout. This is the facilitator’s control panel
for this tool session.&lt;/p&gt;
&lt;h3&gt;Tool instance view layout&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│ [Tool name]                    [● Preparing]  [node view ↗]    │
│ [Phase] · [Movement] · [Date created]                           │
│ Reference: [ref tool name →] (clickable, navigates to ref node) │
├─────────────────────────────────────────────────────────────────┤
│ TABS: [ Setup ] [ Groups n ] [ Contributions n ] [ Summary ]    │
├─────────────────────────────────────────────────────────────────┤
│ [tab content]                                                    │
└─────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Status badges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;preparing&lt;/code&gt; → amber · “Preparing”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;active&lt;/code&gt; → accent · “Active”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;complete&lt;/code&gt; → muted blue · “Complete”&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Setup tab&lt;/h3&gt;
&lt;p&gt;Shows the tool steps, editable before Start is pressed. Read-only after.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;STEPS  (editable until started)

  1. [Step title — editable input]
     [Step body — editable textarea]
     [capture inline: ○ yes ● no]
     [↑ move up] [↓ move down] [+ insert after] [× remove]

  2. ...

  [+ Add step]

──────────────────────────────────────────────
RESOURCES
  Format: group · Indoors · Synchronous · 60min+ · Low tech
  (rendered from ref tool meta filter values — read only here)

──────────────────────────────────────────────
[ Start tool → ]   (disabled until at least one group has ≥1 named member)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a step is edited (title or body changed from the original):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Record the variation in meta.local_variations&lt;/li&gt;
&lt;li&gt;Show a small “modified” indicator next to that step&lt;/li&gt;
&lt;li&gt;A “reset to original” link restores the reference text&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;“Start tool →” button:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sets tool_instance meta.status = “active”, meta.started_at = now&lt;/li&gt;
&lt;li&gt;Saves via PUT /api/nodes/:id&lt;/li&gt;
&lt;li&gt;Switches to Groups tab&lt;/li&gt;
&lt;li&gt;Steps become read-only&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Groups tab&lt;/h3&gt;
&lt;p&gt;A grid of group cards — one per group_instance child node.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GROUPS  3                                    [+ Add group]

┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│ GROUP 1         │  │ GROUP 2         │  │ GROUP 3  📄     │
│ ● digital       │  │ ● digital       │  │ ○ paper         │
│                 │  │                 │  │                 │
│ Tom P    mapper │  │ [empty]         │  │ [empty]         │
│ Sarah K  noter  │  │                 │  │                 │
│ Amara D  walker │  │                 │  │                 │
│                 │  │                 │  │                 │
│ not started     │  │ not started     │  │ not started     │
│ [Edit]          │  │ [Edit]          │  │ [Upload] [Edit] │
└─────────────────┘  └─────────────────┘  └─────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Group card states:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;not_started&lt;/code&gt; → dim border&lt;/li&gt;
&lt;li&gt;&lt;code&gt;in_progress&lt;/code&gt; → accent border, step progress indicator&lt;/li&gt;
&lt;li&gt;&lt;code&gt;submitted&lt;/code&gt; → green border, “✓ submitted”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;paper_pending&lt;/code&gt; → amber border, “📄 awaiting upload”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Modality toggle:&lt;/strong&gt; Each card has a small toggle: &lt;code&gt;● digital / ○ paper&lt;/code&gt;.
Switching to paper shows “📄” badge and adds Upload button.
Available before and during the session (groups can switch if device fails).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit group (inline panel below the card):&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Opens inline when Edit is clicked:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Group 1  ● digital  ○ paper

Members:
  Name: [Tom P      ]  Role: [mapper  ]  [×]
  Name: [Sarah K    ]  Role: [noter   ]  [×]
  Name: [Amara D    ]  Role: [walker  ]  [×]
  Name: [           ]  Role: [        ]  [+ add member]

Roles suggested by this tool: mapper, noter, walker, interviewer
(pulled from ref tool node meta.suggested_roles if it exists)
[Save]  [Cancel]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Names and roles are free text. No validation — blanks acceptable,
duplicates acceptable. Save writes to group_instance meta.members
via PUT /api/nodes/:id.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Upload button (paper groups):&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Opens the image upload flow (existing image attachment feature)
pre-configured for this group instance. On upload completion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sets group_instance meta.uploaded_by = current user id&lt;/li&gt;
&lt;li&gt;Sets group_instance meta.on_behalf_of = group_instance_id&lt;/li&gt;
&lt;li&gt;Sets group_instance meta.status = “submitted”&lt;/li&gt;
&lt;li&gt;Creates a contribution node as child of the group_instance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;+ Add group button:&lt;/strong&gt;
Creates a new group_instance node as child of this tool_instance.
Auto-numbers (Group 4, Group 5 etc).&lt;/p&gt;
&lt;h3&gt;Contributions tab&lt;/h3&gt;
&lt;p&gt;All contribution nodes across all group instances for this tool,
displayed as cards.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CONTRIBUTIONS  7                    Filter: [ All ] [ Group 1 ] [ Group 2 ] ...

[contribution card — group name, timestamp, approval status, content preview]
[contribution card]
...

[ + Add contribution ]   (facilitator can add directly — proxy for paper groups)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Matches the contributions area from Phase 3 but scoped to this tool instance.
Group filter tabs pull group names from group_instance nodes.&lt;/p&gt;
&lt;p&gt;“+ Add contribution” opens quick-capture pre-filled:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;type: artefact&lt;/li&gt;
&lt;li&gt;parent: the group_instance_id (not the tool_instance directly)&lt;/li&gt;
&lt;li&gt;meta.tool_instance_id, meta.phase, meta.movement inherited&lt;/li&gt;
&lt;li&gt;meta.approval_status: pending&lt;/li&gt;
&lt;li&gt;meta.uploaded_by: current user (for proxy tracking)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Summary tab&lt;/h3&gt;
&lt;p&gt;Read-only. Available at all times but most useful after completion.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SUMMARY

Status: Active · Started: [datetime]

GROUPS
  Group 1  ●  Tom P · Sarah K · Amara D     submitted  3 contributions
  Group 2  ●  [unnamed]                      in progress  step 2/5
  Group 3  📄  [unnamed]                     paper pending  0 uploaded

ACTIVITY TRACE  (Group 2)
  Step 1   entered 10:23  exited 10:31   (8 min)
  Step 2   entered 10:31  in progress

  ⚠ Group 3 has not submitted. Paper groups need facilitator upload.
  ⚠ Group 2 has been on step 2 for 12 minutes.

CONTRIBUTIONS  7 total · 5 pending approval · 2 approved
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The ⚠ warnings are the facilitator’s nudge system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Paper group not yet uploaded → always show if session is active&lt;/li&gt;
&lt;li&gt;Group on same step for &amp;gt; 10 minutes → show (time threshold configurable
in tool_instance meta, default 10 min)&lt;/li&gt;
&lt;li&gt;Group submitted with 0 contributions → show&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are computed client-side from step_trace timestamps and
contribution counts — no new endpoint needed.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;What does NOT change&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Standard node view — unchanged, accessible via “node view ↗” link&lt;/li&gt;
&lt;li&gt;Reference tool nodes — unchanged (read from, not written to, by instances)&lt;/li&gt;
&lt;li&gt;Project dashboard — unchanged (progress grid already reads contribution counts)&lt;/li&gt;
&lt;li&gt;Auth system — unchanged&lt;/li&gt;
&lt;li&gt;Image map feature — unchanged (used by Upload button for paper groups)&lt;/li&gt;
&lt;li&gt;Quick capture overlay — unchanged (used as base for contribution capture)&lt;/li&gt;
&lt;li&gt;Tree navigation — unchanged (tool_instance and group_instance nodes
appear in tree as children of phase nodes and tool_instances respectively)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;File changes&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;db/database.js          — filter_options table + seed
api/filter-options.js   — GET and POST endpoints
api/tool-instances.js   — POST endpoint (creates instance + group instances)
api/projects.js         — add /api/projects/:id/progress update for tool instances
server.js               — mount new routers
lfti-spine.html         — tool instance view, group management, 
                          filter pill extensibility, boot fetches filter options
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;When you’re done — test in order&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Piece 1:&lt;/strong&gt; As institution_admin, add “Playing fields” as a new location filter option
via the tool browser. It appears as a filter pill immediately. As student,
the add link is not visible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Piece 2:&lt;/strong&gt; Select Body Map and Story Circle on Past — Gather. Click “Start this phase →”.
Two tool_instance nodes appear in the tree as children of Past — Gather.
Each has steps parsed from the reference tool body and a references relation
to the correct ref tool node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Piece 3:&lt;/strong&gt; Expand a tool_instance node. See 3 group_instance child nodes
(or matching suggested_groups count). Each has modality: digital, status: not_started.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Piece 4 — Setup tab:&lt;/strong&gt; Click a tool_instance node. See the dashboard view with
Setup tab active. Steps are editable. Edit one step body — see “modified” indicator
and variation recorded in meta.local_variations. Click “reset to original” —
step body restored.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Piece 4 — Groups tab:&lt;/strong&gt; Switch to Groups tab. See 3 group cards. Edit Group 1 —
add 3 member names and roles, save. Toggle Group 3 to paper — Upload button appears.
Click “+ Add group” — Group 4 appears.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Piece 4 — Start:&lt;/strong&gt; Click “Start tool →” (after adding at least one named member).
Status changes to Active. Setup tab steps become read-only.
Summary tab shows Group 1 with members listed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Piece 4 — Contributions:&lt;/strong&gt; Switch to Contributions tab. Click “+ Add contribution”.
Quick-capture opens. Save a test contribution. It appears in the contributions tab
with “pending” badge and the correct group name.
Summary tab shows updated contribution count and ⚠ for groups with 0 contributions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
</feed>
