WASH R&D Centre, University of KwaZulu-Natal
Decision support · sanitation technology selection

Which sanitation system suits this settlement?

The framework answers that question in a fixed path: the full set of system types, the context measured on the ground, a screen that eliminates what cannot work and names the conditions on what can, a ranking of the survivors on fit and on cost, and a recommendation with its reasons attached.

Step 1

System types: four classes, and how a technology is classified

A technology is classified by three questions, each answerable from its datasheet or a site visit, and the answers place it in one of four classes. The classes are not labels chosen by the provider or the planner. They follow from what the technology does with water and with waste, and each class carries its own regulatory route, its own residuals service and its own evidence standard, which is why the class has to be decided before anything else is.

Figure 1 · Classification tree
Q1 · Is water used to flush? flush volume at the user interface no DRY excreta handled as solids yes Q2 · Is blackwater piped off site to treatment elsewhere? crosses the site boundary by sewer yes SEWERED · WWTP central works or decentralised plant no Q3 · Is treated water recovered on site for flushing or reuse? recirculation or on-site reuse yes WESS NSS that recovers its water no NSS, WATER-BASED contained or treated, not recovered Three questions, each answerable from a datasheet or a site visit. Scale, treatment level and residuals route are attributes recorded after the class is fixed.
Three tests, four classes. Q1 separates dry from water-based. Q2 separates sewered from non-sewered on one observable fact: whether blackwater leaves the site by pipe to a wastewater treatment works somewhere else, a central works or a decentralised plant serving a settlement. Q3 separates, within non-sewered water-based systems, those that recover their treated water from those that contain or treat it without recovery. WESS is therefore a sub-class of NSS, which is how ISO 30500 and the draft South African by-laws define it.
Table 1 · Definitions and what each class implies
ClassDefinitionSourceRegulatory routeResiduals serviceWater demand
DryNo water is used to flush. Excreta are handled as solids, with or without urine diversion, and stored, dried, composted or collected on site.Compendium of Sanitation Systems (Eawag) U.1, U.2On-site sanitation by-laws; FSM guidelines (WRC TT 959/25)Pit or vault emptying, or scheduled container collectionNone
NSS, water-basedWater is used to flush and the blackwater is contained or treated on the site of generation, with the effluent infiltrated, stored for truck-out or discharged. The treated water is not recovered.ISO 30500: sanitation not connected to a networked sewerOn-site sanitation by-laws; general authorisation for infiltration or dischargeTank or pit desludging by truck; conservancy truck-outLow to high, potable
WESSNon-sewered sanitation that treats at or near the point of generation and recovers the treated water for flushing or reuse.WASH Centre de-risking protocol; ISO 30500:2025 (SANS 30500); draft model by-lawsSANS 30500 performance; by-law permission to treat and reuse on site without a water-use licencePeriodic sludge removal from the treatment train; consumables supplyLow, recycled
Sewered · WWTPBlackwater is piped off the site of generation to a wastewater treatment works. The works is the defining element and the municipal decision: a central works with its capacity and licence, or a decentralised plant (DEWATS, packaged plant, satellite works) serving a settlement. Two sub-classes, central and decentralised, carried as an attribute.Compendium conveyance and treatment groups C.1 to C.6, T.3 and T.8 (decentralised), T.12 (works)Works licence and discharge standard (general or special limit); Green Drop at central scaleSludge handled at the worksMedium to high, potable
The chemical toilet is classified NSS, water-based, and flagged interim. Scale (household, communal, settlement, central), treatment level (containment, primary, full treatment), residuals route and power dependency are attributes recorded on every technology after the class is fixed, and they drive the screen and the ranking. They do not change the class.
Table 1b · eThekwini's accepted levels of service, mapped to the four classes
Level of service in the EWS Service Level Standards and draft Sanitation PolicyClassPolicy constraint carried as a rule
Conventional waterborne sanitation: connection to sewerage infrastructureSewered · WWTPSubject to the receiving works' capacity and Green Drop risk class
Waterborne with on-site disposal: septic tank and soakawayNSS, water-basedEmptying by the Sanitation Operations Branch's contractors
Waterborne with on-site collection and off-site disposal: conservancy tank, tankerNSS, water-basedTruck-out interval and route are the cost
Urine-diversion double-vault toilet (dry sanitation)DryPolicy default for unsewered single households without a metered water connection; not permitted at metered premises; emptied every two years
Ventilated improved pitDryNo new VIPs permitted; existing ones serviced every five years. The catalogue keeps the VIP as a system and the policy rule eliminates it for new provision in eThekwini
Community ablution block on sewer or septic (informal settlements)Sewered · WWTP or NSS, water-basedThe policy standard for informal settlements; the class follows the pipe
Chemical toiletNSS, water-based interim onlyEmergency and interim provision
Decentralised treatment, non-sewered with treatment, WESSWESS and decentralised Sewered · WWTPNo category in the current policy. The framework supplies the category and the strategic development plan proposes the policy amendment
The framework speaks the municipality's language. A municipal policy is a second rule source beside the primary-source register: each constraint above becomes a rule row with the policy clause as its source, applied per municipality, so that a system the policy excludes is eliminated with the clause named. Sources: EWS Service Level Standards, 18th edition, p. 6; draft Sanitation Policy §6.4 and §7.2.
Table 2 · Classification criteria
QuestionObservableTestDecides
Q1 · Is water used to flush?Flush volume per use at the user interface, from the datasheet or measuredNo water added for conveyance of excreta: dry. Any pour or cistern flush, including chemical units: water-baseddry vs water-based
Q2 · Is blackwater piped off site to treatment elsewhere?Where the blackwater pipe ends: on the site of generation, or at a treatment step under a different location or operatorPipe crosses the site boundary to a treatment works elsewhere, by conventional, simplified or solids-free sewer: sewered · WWTP. Record whether the works is central or decentralised. Reticulation within one site, such as a school compound or an ablution block to its own plant, is not a sewersewered vs non-sewered
Q3 · Is treated water recovered on site?Fate of the treated effluent: recirculated to flush, reused on site, infiltrated, stored, or dischargedTreated water returned to the cistern or reused on site as the design intent, with a treatment train that reaches a reuse standard: WESS. Infiltration, truck-out or discharge without recovery: NSS, water-basedWESS vs NSS
The tests are ordered. A dry system is never asked Q2 or Q3, and a sewered system is never asked Q3, because a works that reuses its effluent is still a sewered system. Where a datasheet is silent on Q3, the technology is classified NSS until recovery is demonstrated, since the WESS class carries a reuse permission that has to be earned.
Figure 2 · Catalogue systems by water demand and scale, coloured by class
None Low10–25 L/p/d Medium25–60 L/p/d High> 60 L/p/d water demand per person per day Household Settlement Central VIP (S.3)UDDT (S.7)Composting (S.8)Container-basedPour-flush pits (S.6)Recirculating unitSeptic + soakaway (S.9)Conservancy tank (S.17)Communal WESSSettled sewer (C.2)DEWATS (S.10 + wetland)Packaged plantSimplified sewer → T.1Conventional sewer → T.1
DryNSS, water-basedWESSSewered · WWTP
The classes fall into bands on the water axis. Dry at none, WESS at low and recycled, NSS water-based from low to high, sewered to a works from medium up. Scale is an attribute: WESS runs at household and communal scale, and the works row separates the decentralised plants at settlement scale from the central works.
Table 3 · Sixteen systems through the three tests
SystemQ1 flushQ2 off siteQ3 recoveredClassComponent chainWaterScale
Ventilated improved pit (VIP) with FSMno——DryU.1 dry toilet → S.3 VIP → collection → treatmentNoneHousehold
Urine-diverting dry toilet (UDDT)no——DryU.2 UDDT → S.7 dehydration vault · S.1 urine storage → reuseNoneHousehold
Composting systemno——DryU.1 dry toilet → S.8 composting chamber → reuseNoneHousehold or communal
Container-based sanitation, servicedno——DryU.1 / U.2 → S.16 storage container → scheduled collection → treatmentNoneHousehold
Pour-flush to twin leach pitsyes, pournonoNSS, water-basedU.4 pour flush → S.6 twin pitsLowHousehold
Septic tank with soakaway and FSMyesnonoNSS, water-basedU.5 cistern flush → S.9 septic tank → S.15 soakaway · sludge to treatmentMedium to highHousehold
Conservancy tank, scheduled truck-outyesnonoNSS, water-basedU.5 cistern flush → S.17 conservancy tank → transport → treatmentHighHousehold
Recirculating household unityesnoyesWESSU.5 / U.8 leak-free flush → on-site treatment with recirculation (field record)Low, recycledHousehold
Communal WESS with ablution blockyesnoyesWESSAblution block → biological and polishing treatment with recirculation (field record)Low, recycledCommunal
Settled (small-bore) sewerageyesyes—Sewered · WWTPU.5 → S.9 interceptor tank → C.2 solids-free sewer → T.2 DEWATS or satellite worksMediumSettlement
DEWATS: ABR with wetlandyesyes—Sewered · WWTPU.5 → C.1 simplified sewer → S.10 ABR → constructed wetland → reuse or dischargeMedium to highSettlement
Packaged treatment plant serving a settlementyesyes—Sewered · WWTPU.5 → C.1 simplified sewer → packaged biological plant → discharge or reuseHighSettlement
Simplified or condominial sewerage to a worksyesyes—Sewered · WWTPU.5 → C.1 simplified sewer → T.1 conventional worksMedium to highSettlement to central
Conventional sewerage to a central worksyesyes—Sewered · WWTPU.5 → C.3 conventional gravity sewer → T.1 conventional worksHighCentral
Community ablution block on sewer or septicyesyes / nonoSewered · WWTP or NSS, water-basedU.5 cistern flush (block) → C.3 sewer → T.1 works, or → S.9 septic → S.15 soakawayMedium to highCommunal
Chemical toilet (interim)yes, chemicalnonoNSS, water-basedServiced chemical unit → transport → treatmentNoneHousehold or communal
Codes are the Compendium's (U user interface, S on-site storage or treatment, C conveyance, T treatment, D use or disposal); CEN codes are the Centre's. A packaged plant treating a single facility's blackwater on its own site, with discharge and no recovery, is NSS water-based rather than sewered; the same plant serving a settlement through a small sewer is sewered. The class follows the pipe, not the product.
On the live system · the four classes as categories of product
The Units tab of the system: the five categories in the control column with their counts of catalogued templates and company units, and one box per category of twenty-year cost per household across its templates. The class is decided before anything else, and the tab is read by class.
The Units tab of the system: the five categories in the control column with their counts of catalogued templates and company units, and one box per category of twenty-year cost per household across its templates. The class is decided before anything else, and the tab is read by class.
The Units tab of the system: the five categories in the control column with their counts of catalogued templates and company units, and one box per category of twenty-year cost per household across its templates. The class is decided before anything else, and the tab is read by class.
Table 4 · Benchmarking providers within a class
Metric familyDryNSS, water-basedWESSSewered · central WWTPSewered · decentralised plant
Treatment performance
output against the class's standard
Pathogen inactivation in the residual: helminth ova, E. coli in dried or composted product; moisture and C:N for land application
FSM guidelines WRC TT 959/25 · protocol sludge methods
Effluent to ground or discharge against the general authorisation values: COD, TSS, E. coli, nutrients; tank sludge accumulation and settling
DWS general authorisation · protocol settling and accumulation methods
Treated water against ISO 30500 (SANS 30500) at the recirculation line, bowl and greywater outlet: E. coli, total coliforms, COD, BOD, TSS, TDS, N, P, colour; free chlorine 0.2–0.5 mg/L
ISO 30500:2025 · protocol Part VII · 16-step site checklist
Discharge against the general or special limit; works compliance and risk rating under Green Drop; capacity utilisation against design
National Water Act discharge standards · Green Drop
Discharge against the general or special limit at the plant outlet; reuse quality where effluent is reused
National Water Act discharge standards · protocol Part VII where reused
Process health
the reactor, where there is one
no reactor · composting temperature and turning record where composting Septic and package units: settling, sludge blanket, DO and ORP where aerated
protocol FMHI, subset
Functional Microbial Health Index: COD profile, DO profile, oxygen uptake, ORP, pH stability, nitrogen transformation, turbidity/TSS, biomass structure → green / amber / red per compartment
protocol Part VII, FMHI scorecard
Works process control: sludge age, DO, settleability, nutrient removal per unit process
works operator records · Green Drop process audit
Functional Microbial Health Index on the ABR, wetland or packaged reactor, as for WESS
protocol FMHI
Operational reliability
is it working, continuously
Fill rate against design life; vault or container availability; odour and fly complaints gap Uptime; overflow and backup events; pump availability where pumped gap Percentage uptime; percentage of time within specification; live rating A to E with sensor liveness as the confidence term
InfraTrack · protocol Part X
Time within discharge limits; bypass and overflow events; pump-station availability on the trunk system
Green Drop · works records
Percentage uptime; percentage of time within limits; live rating where sensored
InfraTrack · protocol Part X
Service reliability
scheduled tasks done and recorded
Emptying or collection on schedule and recorded; safe handling compliance
O&M sign-off machinery · FSM guidelines
Desludging on schedule and recorded; truck-out interval kept
O&M sign-off machinery
Provider scorecard: schedule adherence, incident reporting, revision reporting; consumables provisioned; named maintenance party in place
1 Sep provider scorecard · HAZOP register closure rate
Sewer blockage response time; works maintenance schedule kept and recorded
municipal records
Plant maintenance schedule kept and recorded; desludging of the ABR on schedule; named operating party
O&M sign-off machinery
Residuals
handled safely, to a known end point
Sludge or product removed to a licensed disposal or treatment point; fraction valorised
FSM guidelines
Sludge to a licensed treatment point; disposal route recorded
FSM guidelines
Sludge removal from the treatment train on schedule; helminth ova and pathogen load in the residual; valorisation pathway
protocol sludge characterisation
Sludge handled at the works to the works licence; sludge classification for disposal or beneficial use
works licence · sludge guidelines
Sludge removed from the plant on schedule to a licensed point
FSM guidelines
User side
what the user experiences
Cleanliness, odour, privacy and safety of shared access; user acceptance gap Availability of flush water; odour; blockage frequency gap Colour, odour and clarity at the interface; front-end blockage events from inserted materials; availability
protocol checklist steps 13 and 16 · HAZOP categories
Blockage and overflow complaints on the network; availability
municipal complaint records
Blockage and overflow complaints; odour at the plant; availability
municipal records
Cost
per household per year, actual
Emptying cost per event and per year; product revenue where any Desludging cost per year; water cost of flushing Consumables, energy and maintenance per year; water saved against a flush baseline
protocol Part XII cost de-risking
Tariff-recovered cost; energy and chemical cost at the works per household connectedEnergy, chemical and maintenance cost per household served; sludge removal cost
Same families, different numbers. A provider is benchmarked only against providers in the same class, on that class's standard and sampling points. The WESS column is held in full in the de-risking protocol and InfraTrack. The two sewered columns are national and public at central scale, and the decentralised column reuses the WESS instruments because the reactor is the same kind of thing. The dry and NSS columns hold the standards and the service metrics but no provider record yet, and the cells marked gap are to be filled from the FSM guidelines and the first monitored sites of those classes, not defaulted.
On the live system · providers within the water-efficient class
The recirculating (WESS) category picked: the chips count its templates, units, companies and monitored sites; the units are listed by company with the template each instantiates and the sites it is monitored at; the picked unit (WEC NEWgen 800) shows its company, template, status, the numbers a source states (or
The recirculating (WESS) category picked: the chips count its templates, units, companies and monitored sites; the units are listed by company with the template each instantiates and the sites it is monitored at; the picked unit (WEC NEWgen 800) shows its company, template, status, the numbers a source states (or
The recirculating (WESS) category picked: the chips count its templates, units, companies and monitored sites; the units are listed by company with the template each instantiates and the sites it is monitored at; the picked unit (WEC NEWgen 800) shows its company, template, status, the numbers a source states (or
The recirculating (WESS) category picked: the chips count its templates, units, companies and monitored sites; the units are listed by company with the template each instantiates and the sites it is monitored at; the picked unit (WEC NEWgen 800) shows its company, template, status, the numbers a source states (or "not stated"), the category's observed uptime, and its monitored site with the hazard categories recorded there.
Step 2

Context: what is measured

A settlement is described by sixteen measurements. Most are physical and can be read from a site visit, a soil test and a map. Three describe the people and the institution: water availability, operating capacity, and reuse interest. Each is stored as measured and evaluated in the band the rules read, so the record says both "water table 3.2 m" and "evaluated in the 2 to 5 m band".

Table 5 · Context profile
MeasurementBands used in the screenRole
Housing density<50 · 50–150 · 150–300 · >300 households/hagate
Mean plot size<100 · 100–200 · 200–500 · >500 m²gate
Water supply typenone · borehole · tanker · standpipe · yard tap · house connectiongate
Water availability<10 · 10–25 · 25–60 · 60–100 · >100 L/person/daygate · score
Water table depth<2 · 2–5 · 5–10 · 10–20 · >20 mderived → risk
Soil typetwelve classes, fractured rock to silty clayderived → risk
Percolation rate>1000 · 300–1000 · 100–300 · 25–100 · 15–25 · 8–15 · <8 mm/hgate
Terrain<25° · >25°gate
Flood proneyes · nogate
Vehicle accessnone · peripheral · partial · fullgate
Distance to main sewer<1000 · >1000 mderived → sewer availability
Receiving works: operational capacity and riskpercent of design inflow; Green Drop cumulative risk class (low · medium · high · critical); microbiological compliancegate · derived → sewer availability
Settlement upgrading categoryA rapid formalisation · B1 incremental upgrading · B2 deferred relocation · C immediate relocationgate: B2 and C admit interim systems only
Local operating capacitylow · medium · highscore
Reuse interest, household and communityyes · noscore
Cleansing practice and user-interface settingwater · soft paper · hard material; household · communalgate: user-interface rules
The last measurement, cleansing practice and the household or communal setting of the toilet, feeds the user-interface rules. The bands are the register's, each with the document that set it. Two measurements are the municipality's: the receiving works' capacity and risk class come from the Green Drop report per works (in eThekwini, Craigieburn at 132 percent of design, Tongaat Central and Umhlanga at 150 percent, Central, Southern and Phoenix at zero microbiological compliance in 2023; Green Drop 2023, eThekwini chapter, pp. 203 ff.), and the upgrading category comes from the IDP's settlement register, which lists every informal settlement with its ward, household count and category.
On the live system · a site's variables as recorded
The Sites tab for the dense-settlement archetype Z1: one row per variable with its unit and cut points, the recorded band highlighted, and the evidence tier beside it; the two derived variables (groundwater pollution risk from soil class and water-table depth, works headroom from the receiving works) computed and greyed at the foot. The chips above count the variables recorded, those below the evidence floor, and the latest verdict.
The Sites tab for the dense-settlement archetype Z1: one row per variable with its unit and cut points, the recorded band highlighted, and the evidence tier beside it; the two derived variables (groundwater pollution risk from soil class and water-table depth, works headroom from the receiving works) computed and greyed at the foot. The chips above count the variables recorded, those below the evidence floor, and the latest verdict.
The Sites tab for the dense-settlement archetype Z1: one row per variable with its unit and cut points, the recorded band highlighted, and the evidence tier beside it; the two derived variables (groundwater pollution risk from soil class and water-table depth, works headroom from the receiving works) computed and greyed at the foot. The chips above count the variables recorded, those below the evidence floor, and the latest verdict.
Figure 3 · Two measurements become one risk class (Groundwater Protocol vulnerability classes)
Soil type< 2 m2 – 5 m5 – 10 m10 – 20 m> 20 m
Fractured rockExtremeExtremeHighHighMedium
GravelExtremeHighHighMediumLow
Sand, loamy sandExtremeHighMediumLowLow
Loam, silt, sandy loamHighMediumMediumLowNegligible
Clay, clay loamHighMediumLowNegligibleNegligible
ExtremeHighMediumLowNegligibleOutlined: the worked example, sandy loam at 3.2 m
Groundwater pollution risk is derived, not entered. Soil type against water table depth gives the risk class that every pit, soakaway and tank rule reads. Sewer availability is derived the same way from distance to sewer and works capacity.
Step 3

Screen: what cannot work, and what can work with conditions

Every system in the catalogue is tested against every gate criterion in the context. The rules are written against components, never against systems, and each names the document it rests on: the Groundwater Protocol for pits, tanks and soak pits against the water table, the national standards for percolation and setbacks, the faecal sludge guidelines for emptying access, the Compendium's technology sheets for water requirement, flooding, terrain and density, ISO 30500 for the water-efficient units, and the Green Drop register for the works. The municipality's policy rules sit beside them. A verdict has three values. Pass means the component is appropriate on that criterion. Fail eliminates the system. Conditional lets the system through with a named condition attached, written as an obligation: a lined pit 30 m from any abstraction point, a low-flush cistern, a long-hose route from the periphery. The register holds 309 rule rows over 26 components and 13 criteria, and a context that presents a band no rule covers is an error the engine raises, never a pass.

Figure 4 · A system inherits the worst verdict along its chain (rules from the register)
SYSTEM · septic tank with soakaway U5 Cistern-flush toilet user interface S9 Septic tank on-site treatment D7 Soak pit disposal blackwater effluent System = worst of chain Flood prone: yes pass cond · anchored, sealed fail FAIL · eliminated Percolation: 8 to 15 mm/h pass pass cond · enlarged soakaway COND · survives
Both rows are rule rows of the register. A flood-prone site eliminates the system because the soak pit fails (Compendium D.7), and the reasons trail names the soak pit. A slow-draining soil lets the system through with the soak pit's condition attached to the recommendation (SANS 10252-2).
On the live system · a condition attached as an obligation
Septic tank with soakaway on the peri-urban archetype Z2: the option survives with conditions, and the evidence pane names each rule in words (the variable, its band, what follows), then its code, the document behind it and its grade. The condition is written as an obligation the municipality accepts at closing.
Septic tank with soakaway on the peri-urban archetype Z2: the option survives with conditions, and the evidence pane names each rule in words (the variable, its band, what follows), then its code, the document behind it and its grade. The condition is written as an obligation the municipality accepts at closing.
Figure 5 · Three verdicts
Gate component × band pass conditional survives, condition attached to the recommendation Ranking step 4 fail eliminated · the component and criterion are kept as the reason
Conditions are part of the answer. "Off-site effluent disposal required" on a septic system is a design obligation and a cost line, and the recommendation carries it. A survivor with three conditions and a survivor with none are different recommendations even at the same score.
On the live system · a system ruled out, with the deciding rules kept as the reason
The same system on the dense archetype Z1: ruled out, and the evidence pane keeps every failing rule (water supply type, water availability, housing density on the tank and on the soak pit) with its document and grade. The system stays in the list so the reader sees why no other option is proposed.
The same system on the dense archetype Z1: ruled out, and the evidence pane keeps every failing rule (water supply type, water availability, housing density on the tank and on the soak pit) with its document and grade. The system stays in the list so the reader sees why no other option is proposed.
Step 4

Rank: fit and cost, side by side

Survivors are ranked twice and the two rankings are never blended. Fit is a weighted score on the register's per-system values, construction ease, space, further treatment, reuse potential and water required, on the two cost criteria read from the cost model against a reference cost, and on the operating-risk criteria the WASH Centre field record adds: front-end robustness to inserted materials, dependency on consumables, dependency on desludging and truck access, the skill the maintenance schedule requires against local capacity, and whether the system can be monitored continuously. The planner's three goals from five, water-sensitive design, resource reuse, low cost, minimal maintenance, local jobs, double the weight of the criteria they touch.

Cost is the twenty-year cost per household as a present value: capital, operating cost including consumables and energy, desludging or collection at the frequency and route cost the context implies, and refurbishment on each component's service life.

Figure 6 · Ranking surface (illustrative values, worked example below)
0 25 50 75 100 fit score 0 20k 40k 60k 80k 20-year cost per household, R (present value) Communal WESS 3 conditions DEWATS + simplified sewer 2 conditions Container-based service 1 condition Household UDDT 1 condition
Fit up, cost across, conditions on each point. Two systems close on fit and apart on cost is the normal shape of the answer, and the planner sees the trade rather than a single number that hides it.
On the live system · fit beside cost, never blended
The Suitability tab for Z2, where eleven options survive: the options as cards, the recommendation first then by fit, each with its fit, its twenty-year cost and capital per household, and its risks and concerns in words; beside them the survivors as points, fit up and cost across, coloured by verdict. Two systems close on fit and apart on cost is the normal shape of the answer.
The Suitability tab for Z2, where eleven options survive: the options as cards, the recommendation first then by fit, each with its fit, its twenty-year cost and capital per household, and its risks and concerns in words; beside them the survivors as points, fit up and cost across, coloured by verdict. Two systems close on fit and apart on cost is the normal shape of the answer.
The Suitability tab for Z2, where eleven options survive: the options as cards, the recommendation first then by fit, each with its fit, its twenty-year cost and capital per household, and its risks and concerns in words; beside them the survivors as points, fit up and cost across, coloured by verdict. Two systems close on fit and apart on cost is the normal shape of the answer.
Step 5

Result: a worked context

An illustrative dense settlement, run through the five steps. The planner chose low cost, minimal maintenance and water-sensitive design as goals.

Context profile
Density250 HH/ha
Plot size< 100 m²
Wateryard tap · 25–60 L/p/d
Water table3.2 m
Soilsandy loam
GW risk (derived)medium
Percolation25–100 mm/h
Flood proneno
Accesspartial
Sewer> 1000 m · works at capacity
Operating capacitylow
Reuse interestcommunity: yes
Survivors, ranked on fit · cost beside
1
Communal WESS with ablution block
fit 74 · about R38k per household over 20 years
cond consumables provisioning · front-end protection · named maintenance party against low operating capacity
2
DEWATS with simplified sewer
fit 71 · about R52k
cond land for the treatment step · off-site effluent disposal
3
Container-based service
fit 58 · about R61k
cond partial vehicle access: collection route to be confirmed
4
Household UDDT
fit 55 · about R29k
cond plot under 100 m²
Eliminated, with the deciding rule
✕
VIP, composting
S.3 / S.8 · housing density 150–300: inappropriate
✕
Septic tank with soakaway
S.9 · density: inappropriate · percolation 25–100: inappropriate
✕
Pour-flush twin pits
S.6 · housing density 150–300: inappropriate
✕
Conservancy tank
S.17 · housing density 150–300: inappropriate
✕
Conventional and simplified sewerage to the works
sewer availability: no (distance > 1000 m, works at capacity)
✕
Recirculating household unit, settled sewer, packaged plant
plot size < 100 m² · works at capacity · water availability

The recommendation is the top row with its conditions, the second row as the alternative, and the eliminated list as the reason no other system is proposed. Every line traces to a criterion, a band and a rule, which is what makes it defensible in a room. The values are illustrative of the surface and are not a calibrated run.

On the live system · the worked context is the dense archetype Z1
The Suitability tab for Z1 under the municipality's draft policy: the recommendation (UDDT, fit 70.2, R32 254 per household over twenty years), five suitable options, eleven ruled out, none excluded by policy; every card carries its verdict, its numbers and its reasons, and the closing trail beneath prints the steps. The values are the register's assumed values, not a calibrated run.
The Suitability tab for Z1 under the municipality's draft policy: the recommendation (UDDT, fit 70.2, R32 254 per household over twenty years), five suitable options, eleven ruled out, none excluded by policy; every card carries its verdict, its numbers and its reasons, and the closing trail beneath prints the steps. The values are the register's assumed values, not a calibrated run.
The Suitability tab for Z1 under the municipality's draft policy: the recommendation (UDDT, fit 70.2, R32 254 per household over twenty years), five suitable options, eleven ruled out, none excluded by policy; every card carries its verdict, its numbers and its reasons, and the closing trail beneath prints the steps. The values are the register's assumed values, not a calibrated run.
Position

Where this stands in the literature

The framework is not a new selection algorithm. Santiago generates options more completely and DMsan characterises sustainability more fully. The claim is a municipal decision method that is verifiable line by line, that takes the municipality's own policy and registers as inputs, that turns conditional verdicts into commissioning obligations, that benchmarks providers within class on the field record, and that recalibrates from monitored outcomes. The gap it addresses is the one Ramôa and colleagues documented in 2018: the process guides exist and practice does not follow them.

Table 6 · Aspect by aspect: the precedent, and what the framework takes and adds
AspectPrecedentTakenAdded
ClassificationCompendium of Sanitation Systems and Technologies (Tilley et al. 2014): products, five functional groups, waterless versus water-based. ISO 30500:2025 defines non-sewered; ISO 31800:2020 the sludge units.The component chain as the unit of composition; the waterless split, the conveyance group and the ISO definition as the three tests.Four classes each with a decidable test; the treatment works explicit as a class; the municipality's accepted levels of service mapped onto the classes.
Selection toolsSantiago (Spuhler et al. 2020) generates coherent chains and screens on appropriateness; the Technology Applicability Framework (Olschewski and Casey 2015) scores a technology in context on a traffic light; MCDA for eThekwini (Salisbury et al. 2018) and DMsan (2023).Hard screen then weighted score; the three-valued verdict; chain composition.Verdict inheritance along the chain as a stated rule; a versioned municipal policy layer as a second rule source; conditions becoming obligations in the de-risking register.
Context criteriaThe Groundwater Protocol (DWAF 2003), SANS 10252-2 and 10400-Q, WRC TT 959/25 and the Compendium's technology sheets as the sources of the site criteria; Santiago's appropriateness profiles; WHO Guidelines on Sanitation and Health (2018) and Sanitation Safety Planning (2022); Mitra, Narayan and Lüthi (2022) on criteria for a city-wide mix.The physical criterion set and its bands.Receiving works' capacity and Green Drop risk class per works; the settlement's upgrading category as a gate on permanent versus interim systems.
Lifecycle costDaudey (2018): six of fifty studies costed the whole life; O&M 6 to over 60 percent of total; methods opaque. WASHCost categories; the 2020 standard costing model; Gambrill et al. (2020) on investment drivers; the 2024 systematic review on comparability.Twenty-year present value per household with the WASHCost categories; whole-chain costing; cost beside fit.No unsourced cost is shown; every parameter carries a document.
BenchmarkingISO 30500 and 31800 product tests; Green Drop's weighted score (effluent 30 percent) and its critics (Ntombela et al. 2016; Graham et al. 2025); Strande (2024) on integrating NSS advances with monitoring; soft-sensor and surrogate monitoring literature and its calibration rule.ISO limits for WESS; Green Drop for central works; laboratory rotation calibrating the sensor stream.One matrix of seven metric families by class; providers benchmarked within class only; the gaps named.
Operating riskMkhize et al. (2017): 17,499 UDDT households in eThekwini, smell, pedestal failure, emptying; Crous et al. (2013) on CAB demand; Shyu et al. (2021): 534 days of NEWgenerator operation in an eThekwini settlement; the DEWATS O&M manual; the 2023 emptying review.The failure modes as the five operating-risk criteria.Scoring them from a HAZOP register per category across monitored sites, and recalibrating from outcomes; the UDDT survey as the calibration case for the dry class.
PortfolioCitywide Inclusive Sanitation (Schrecongost et al. 2020); Spuhler and Lüthi (2020) finding planning still one-size-fits-all; shit-flow diagrams as the baseline instrument.The technology-mix principle; the settlement typology as the planning unit.Shared works capacity consumed in sequence, the envelope and phasing to a named count within specification, and the homogeneity trade, computed rather than stated.
Santiago is the closest relative, and the paper positions the framework as a municipal, verifiable specialisation of it rather than a competitor.
Sections to develop

What turns the framework into a method

The five steps above fix the structure. A method is a structure a second team can run and get the same answer from, and that needs five further sections, each staked out below with what has to be unpacked into it, what evidence it rests on, and the test that says it is done. Together they are the white paper's sections 4 to 7 and 10.

Each section now carries its model: the equations, the parameters they read, and a first run. Every parameter in the method has one of three statuses, printed beside any result that depends on it. sourced means a named document supplies the value. assumed means a planning assumption of stated basis, adjustable in the register and to be replaced by a sourced value. missing means no value, and anything that needs it is shown as not computable. The register at publication holds 20 sourced and 164 assumed parameters and no missing ones, so every number below computes, and the assumptions are the work that remains rather than the model. A result that rests on assumed parameters may close an assessment only when the planner accepts the assumption list as a named condition, which is the same mechanism the screen uses for any other condition.

A · Rules from primary sources

done 4 Sep 2026

Every gate rule in the screen is a row citing the document it rests on, with a grade, and every band a context can present to a component that reads the criterion has a rule.

SourcesThe Groundwater Protocol (DWAF 2003) for pits, tanks and soak pits against the water table and for the soil-by-depth lookup; SANS 10252-2 for percolation and soakaway sizing and SANS 10400-Q for setbacks; the faecal sludge guidelines (WRC TT 959/25) for emptying access; the Compendium's technology sheets for water requirement, flooding, terrain and density; ISO 30500 for the water-efficient units; the Green Drop register for the works; the eThekwini Service Level Standards for connection distance and last-resort systems; the de-risking field record for the Centre's components.
FamiliesA rule is written against a family where the source speaks about the family (every pit, every sewer, every soak pit) and against one component where it speaks about that component, and the engine expands a family rule to its members at import. 309 rows over 26 components and 13 criteria: 124 read directly from a standard or protocol (A), 72 derived from a source statement (B), 113 bounded assumptions from the Compendium's applicability notes (C).
Sixteen systemsEach declared as a chain of catalogue codes, Compendium codes where the component is the Compendium's and CEN codes for the Centre's, with the three classification answers recorded as data.
The municipal policy layerA second rule source, per municipality: eThekwini's draft Sanitation Policy and Service Level Standards yield rule rows (no new VIPs; UD default for unsewered single households without metered water; no UD at metered premises; CAB on sewer or septic for informal settlements; chemical toilets interim; B2 and C settlements interim only), each with the clause as its source, versioned against the policy date.
CoverageA context that presents a band no rule covers is an error the engine raises, never a pass; the count of such gaps is the register's first test and is zero.
doneThe register is printed in full (tables/rules.md) and exported as data for the platform. Every non-pass row carries a condition written as an obligation and the document behind it. Signed off 5 September 2026 (owner): the seven failing grade C rows kept; the two thresholds the register had attributed to the Service Level Standards (the density cut points, the 1000 m connection distance) relabelled as planning assumptions to confirm with EWS; the water-efficient family conditional at very high density and on plots under 100 m², where the field record has no site yet; the sewered-to-works reuse value 0.67 → 0.33. The six rows citing SANS 10252-2 and SANS 10400-Q rise to B when the two standards are on file and their clauses quoted; the pack is PublonCore/tasks/todo-sanpath-signoff.md.
On the live system · the register as rows the engineer reads
Left: the soak pit (D7) picked in the Register tab's components register, with its group, family, source and the templates that carry it, and every rule it reads listed with band, verdict, condition, document and grade. Right: the communal WESS unit's density rows after the sign-off of 5 September, the very-high band now conditional with the field record named as its source. The engine knows how to look up a band and apply a row; it knows nothing about soak pits.
Left: the soak pit (D7) picked in the Register tab's components register, with its group, family, source and the templates that carry it, and every rule it reads listed with band, verdict, condition, document and grade. Right: the communal WESS unit's density rows after the sign-off of 5 September, the very-high band now conditional with the field record named as its source. The engine knows how to look up a band and apply a row; it knows nothing about soak pits.
Left: the soak pit (D7) picked in the Register tab's components register, with its group, family, source and the templates that carry it, and every rule it reads listed with band, verdict, condition, document and grade. Right: the communal WESS unit's density rows after the sign-off of 5 September, the very-high band now conditional with the field record named as its source. The engine knows how to look up a band and apply a row; it knows nothing about soak pits.

B · Numbers on the ranking

first run 3 Sep · sign-off pending

The fit score has declared criteria, declared weights and declared sources, and the ranking is shown to be stable under reasonable changes to the weights.

Register values and cost scoresConstruction ease, space, further treatment required, reuse potential and water required as per-system values read from the Compendium's technology sheets, graded C until the field record supplies them; capital and operating cost scored from the cost model against a reference cost per household.
Operating-risk criteria from the field recordFront-end robustness, consumables dependency, desludging and access dependency, skill required against local capacity, telemetry readiness. Scored per class by counting HAZOP entries per category across the de-risked sites, normalised per site-year, banded with declared cut points. Classes with no monitored site scored from the class definition, with the reasoning written out and marked provisional.
Measured inputs the research suppliesThe receiving works' capacity and risk per works from the Green Drop 2023 report replace a yes/no on works capacity with a number and a class, so the sewered systems score on the actual works they would drain to. The emptying cycles in the Service Level Standards (UD every two years, VIP every five) set the desludging-dependency scores and the cost interval for the dry and NSS classes from the municipality's own standard rather than an assumption.
WeightsA table summing to one hundred, one sentence of justification per row, starting from the weights the InfraTrack matching engine already uses. The planner's goals double the weight of the criteria they touch; the doubling rule is printed.
SensitivityEvery weight perturbed by a fifth, up and down, across the eight de-risked sites and the worked example. Where the top rank moves, the paper says which weight moved it. The fit decomposition is stored with every result so a reader sees which criteria produced a rank.

Model · fit score, operating-risk bands and stability

A system \(T\) is a chain of components \(k\) and scores on twelve criteria \(i\). Two are read from the cost model against reference costs \(\kappa_k\) and \(\kappa_o\) per household assumed, so that a system at or above the reference scores zero and one at no cost scores one. Five are per-system values \(f_{T,i}\) of the register, read from the Compendium's technology sheets assumed. Five come from the operating-risk register \(q_{c,i}\) of the system's class \(c\).

\[ s_{T,i} = \begin{cases} \max\!\big(0,\ 1 - k_T/\kappa_k\big) & i = \text{capital} \\[4pt] \max\!\big(0,\ 1 - (C_T - k_T)/\kappa_o\big) & i = \text{operating} \\[4pt] f_{T,i} & i \text{ a register value} \\[4pt] q_{c(T),i} & i \text{ an operating-risk criterion} \end{cases} \]
\[ S_T = 100\,\frac{\sum_i w_i\, g_i\, s_{T,i}}{\sum_i w_i\, g_i}, \qquad g_i = \begin{cases} \gamma & i \text{ touched by a selected goal} \\ 1 & \text{otherwise} \end{cases}, \quad \gamma = 2 \]

The operating-risk score of a class on a criterion is a band of the hazard-register count \(n\) per site (per site-year once the monitored period is known), with cut points \(c_1 = 0.5\) and \(c_2 = 1.0\) assumed:

\[ q(n) = \begin{cases} 1.00 & n = 0 \\ 0.75 & 0 < n \le c_1 \\ 0.50 & c_1 < n \le c_2 \\ 0.25 & n > c_2 \end{cases} \]
CriterionWESS sourcedDryNSSSewered centralSewered decentralised
frontEnd0.250.50.50.750.5
consumables0.751.01.01.00.75
desludging0.750.250.251.00.5
skill0.50.750.750.50.5
telemetry0.750.250.50.750.75

The four unmonitored classes carry provisional scores assumed from the class definition, the eThekwini urine-diversion survey and the Green Drop technical-skills scores. Weights \(w_i\), sum \(100\) assumed, one sentence of justification each in the register:

CriterionWeight
capital12
operational12
constructionEase6
space8
furtherTreatment6
reuse6
waterRequired8
frontEnd10
consumables8
desludging8
skill10
telemetry6

Stability is a fraction. Every weight is perturbed by \(\pm\varepsilon\), \(\varepsilon = 0.2\), in turn, and the index is the share of context and perturbation pairs in which the top rank holds, with a sign-off floor of \(7/9\) contexts unmoved assumed:

\[ \sigma = \frac{1}{2\,|Z|\,|I|} \sum_{z\in Z} \sum_{i\in I} \sum_{\pm} \mathbf{1}\big[\arg\max_T S_T(z;\, w_i(1\pm\varepsilon)) = \arg\max_T S_T(z;\, w)\big] \]

Run of 4 September 2026 on the primary-source register: \(\sigma = 7/9\) over nine contexts, at the sign-off floor. The two movers are near-ties: the dense settlement with the works at capacity, where the communal water-efficient system and the container-based service sit within a point, and the no-goal context, where the urine-diversion toilet and the simplified sewer do. In the dense settlement the urine-diversion toilet leads on fit at \(72\) against the communal water-efficient system at \(67\), which reverses the paper's illustration, and that is reported rather than adjusted. Two readings are open for sign-off. The register values are right and the framework agrees with the municipality's own default for unsewered households, or the dry class's operating-risk scores are too generous against the survey record. The discrepancy report of section E settles it.

done whenThe operating-risk table is signed off with its HAZOP citations, the weight table is printed, and the top-ranked system is unchanged in at least seven of nine contexts under the sensitivity test.
On the live system · a template's fit values and cost parts
UDDT picked among the catalogued templates: its cost parts under the register's first illustrative discount rate with the count of assumed parameters, its chain as a stepper, and the register's per-system fit values (construction ease, further treatment, reuse, space, water required) as chips.
UDDT picked among the catalogued templates: its cost parts under the register's first illustrative discount rate with the count of assumed parameters, its chain as a stepper, and the register's per-system fit values (construction ease, further treatment, reuse, space, water required) as chips.

C · Sourced cost parameters

modelled on assumptions · sources pending

Every number in the twenty-year cost per household has a named source or a stated assumption, and a cost built on assumptions is shown with its assumption list rather than withheld.

Nine parameters per systemCapital per household; operating cost per year; consumables per year; energy per year; desludging or collection interval; cost per desludging event; route cost per kilometre; refurbishment interval; refurbishment fraction of capital. Each row carries value, unit, source document with page or contract number, and date.
Sources by classWESS from provider quotations on the de-risked sites and the protocol's cost de-risking part. Sewered central from eThekwini reticulation and works unit rates and the cost per kilolitre treated. Sewered decentralised from DEWATS and packaged-plant quotations. NSS and dry from municipal housing and rural sanitation unit rates and the pit-emptying and conservancy contract rates.
The FSM route costThe FSM economic model is cited and not yet located. If it cannot be obtained, route costs are rebuilt from the eThekwini desludging contract rates, which the municipality is asked to make available. The decision is recorded either way.
What the research found and did notThe municipality's ten-year sanitation plan (November 2025) gives the envelopes, R1 to 2 billion for underserved-community sanitation and R4 to 6 billion for works, but no unit costs. The Sanitation Operations Branch holds the UD and VIP emptying contract rates and the CAB programme's capital and caretaker costs, which are the dry and NSS parameters; the municipality is asked to make them available. No public source gives eThekwini per-household costs for any class, so every parameter row will carry a municipal or provider document as its source or stay red.
Discount rateEntered by the planner per municipality from its own capital planning rate, shown on every cost. There is no default anywhere.

Model · twenty-year cost per household

Nine parameters per system: capital \(k\), operating cost \(o\), consumables \(c\), energy \(e\), the desludging or collection interval \(\tau\), the cost per event \(p_e\), the route cost per kilometre \(p_r\), the refurbishment interval \(\tau_r\) and the refurbishment fraction \(\varphi\). A communal unit's figures are divided by the households it serves, \(N\). The route length \(L\) is a context measurement. The discount rate \(\rho\) is entered by the planner, and the two rates below serve the hand-check only.

\[ C_T = k + \sum_{y=1}^{H} \frac{o + c + e + d_y + r_y}{(1+\rho)^{y}}, \qquad H = 20, \qquad k = \frac{K_{\text{unit}}}{N} \ \text{for a communal unit} \]
\[ d_y = n_y\,(p_e + 2 L p_r), \quad n_y = \begin{cases} 1 & \tau \ge 1,\ \tau \mid y \\ 1/\tau & \tau < 1 \\ 0 & \text{otherwise} \end{cases}, \qquad r_y = \begin{cases} \varphi\, k & \tau_r \mid y,\ y < H \\ 0 & \text{otherwise} \end{cases} \]

The stance on sources changes in one respect. A cost with an unsourced parameter was to be withheld. It is now shown with its assumption list, so that the model can be checked and the planner can see which numbers move it, and the closing rule admits it only when that list is accepted as a condition. First run at 2026 prices, \(L = 20\) km, every parameter a planning assumption except the two emptying intervals of the Service Level Standards. Rand per household:

System\(C_T\), \(\rho = 0.06\)\(C_T\), \(\rho = 0.10\)\(k\)Operating (PV)Desludging (PV)Refurbishment (PV)Status
VIP with FSM23,42619,97112,0002,2947,1222,010assumed
UDDT32,25427,79916,0003,44110,5792,234assumed
Composting40,43233,49814,0005,73518,3522,345assumed
Container-based57,27843,9626,00010,32335,7865,169assumed
Pour-flush twin pits28,23924,23214,0002,86710,2031,168assumed
Septic + soakaway55,14349,17235,0004,58811,9043,651assumed
Conservancy tank422,481320,89830,0004,588385,3892,504assumed
Recirculating unit119,77999,51445,00037,85119,48817,441assumed
Communal WESS33,06728,57516,6679,4634786,460assumed
Settled sewerage61,37455,18638,00011,47011,9040assumed
DEWATS61,84452,56328,0006,88222,2724,691assumed
Packaged plant (settlement)128,800102,90632,00032,11651,61513,070assumed
Simplified sewer to works39,74937,23730,0009,74900assumed
Conventional sewer to works55,89653,08845,00010,89600assumed
CAB on sewer59,12249,97026,66721,563010,891assumed
CAB on septic63,14053,25628,00021,5632,14011,436assumed

Two things the first run shows about the model rather than the numbers. The conservancy tank is dominated by its monthly emptying, which is the structural reason the Service Level Standards treat it as a last resort, and the model reproduces that from the parameters alone. And the communal systems are sensitive to \(N\): a block serving \(75\) households costs nearly twice per household what the same block serving \(120\) would, so the service population is a parameter the survey must measure and the strategy must allocate. The hand-check is the model's own test: a present value computed by hand at both rates must match the table.

done whenEvery system is either fully sourced or shown as "cost not computable" with the missing parameters named. A hand-computed present value at two discount rates matches the calculation.
On the live system · the cost model across the catalogue
The dry category's templates with their twenty-year cost and capital per household, and the ranges across all five categories with the metric switched to capital: what the cost register yields before any site is surveyed.
The dry category's templates with their twenty-year cost and capital per household, and the ranges across all five categories with the metric switched to capital: what the cost register yields before any site is surveyed.
The dry category's templates with their twenty-year cost and capital per household, and the ranges across all five categories with the metric switched to capital: what the cost register yields before any site is surveyed.

D · Survey protocol and closing rule

protocol drafted · pilot pending

How the sixteen measurements are gathered, by whom, in what time, from which municipal record or field method, and how the planner closes an assessment into a decision. This is the section the municipality writes with the Centre, and it is what makes the paper a joint one.

One entry per measurementWhat is measured, its unit and band cut points, the source in a municipality's own data (GIS and cadastral layers for density, plot size, sewer distance and slope; billing and GIS for supply type; borehole and geotechnical logs for water table and soil; the works register for capacity; flood lines; desludging and complaints records), the field method where no record exists (site visit for access and setting; a double-ring infiltrometer for percolation; a one-page rubric for operating capacity; the engagement record for reuse interest), who gathers it on the four-tier skills ladder, and how long it takes. Each entry ends with the disallowed shortcut: no measurement is inferred from another.
The closing rule, printed verbatimCandidates are the survivors, less any system the municipal policy layer excludes for the settlement's upgrading category. Exclude any with a condition the planner has not accepted, acceptance naming the responsible party. Exclude any over the budget envelope or with no computable cost. Choose the highest fit; ties go to the lower cost. If none remains, report no fit with the nearest by cost and the rule that excluded each, and never relax a rule automatically.
The zone list existsAppendix 12 of the 2026/27 IDP lists every informal settlement with its planning unit, ward, household count and upgrading category (563 of the 605 carry all four; 339 settlements with 225,799 households are B1, incremental upgrading). It is the zone register the survey protocol starts from, and the category is a context measurement. The works register with capacity and risk per works is the Green Drop chapter. The survey protocol therefore names, for each measurement, which of these the planner opens first.
The pilotThree eThekwini zones surveyed by municipal staff, chosen from Appendix 12: a dense B1 settlement beyond sewer reach, a peri-urban B1 zone on UD or septic service, and a B1 settlement within the catchment of a low-risk works with headroom (Northern, Dassenhoek or Verulam). Each survey timed. The three assessments and their closings become the worked section of the paper.
RevisionWhat was unavailable, what took longest, what staff could not band, folded back into the protocol. The protocol is published in the form the pilot left it, not the form it was drafted in.

Model · survey effort, evidence floor and the closing algorithm

Each of the sixteen measurements \(m\) has a source tier \(t(m)\): a municipal record, a site visit, a field test or an engagement instrument. The effort of a zone is the sum of the hours the tier implies, and its cost the hours at the day rate of the staff tier that gathers it. Hours per measurement \(h_t\) assumed: record \(0.5\), visit \(0.75\), field test \(3.0\), engagement \(2.0\). Day rates assumed: technician \(\mathrm{R}\,2{,}800\), engineer \(\mathrm{R}\,6{,}500\). The pilot replaces both with timed values.

\[ E_z = \sum_{m=1}^{16} h_{t(m)}, \qquad \text{cost}_z = \frac{1}{8}\sum_{m=1}^{16} h_{t(m)}\; \text{rate}_{\text{staff}(m)} \]

With ten measurements from records, three from the visit, one field test and two engagement instruments, a zone comes to about \(17\) staff hours, consistent with the \(\mathrm{R}\,15{,}000\) per zone the plan carries once travel and the assessment itself are added. The evidence floor assumed separates a survey from a guess: a gate measurement must come from a record or a field test, a scoring measurement may come from a record, a visit or an engagement instrument, and a derived criterion inherits the floor of its inputs. An assessment whose gate measurements sit below the floor may be run but may not close.

The closing algorithm, as the tool runs it, with \(\beta\) the capital envelope per household:

\[ \begin{aligned} &1\;\; \mathcal{C} \leftarrow \text{survivors} \setminus \text{policy exclusions for the upgrading category} \\ &2\;\; \mathcal{C} \leftarrow \{T \in \mathcal{C} : \text{every condition of } T \text{ accepted, with a responsible party named}\} \\ &3\;\; \mathcal{C} \leftarrow \{T \in \mathcal{C} : k_T \le \beta \ \text{and}\ C_T \text{ computable}\} \\ &4\;\; \mathcal{C} \leftarrow \{T \in \mathcal{C} : \text{assumption list of } C_T \text{ accepted as a condition, if any}\} \\ &5\;\; T^\star = \arg\max_{T\in\mathcal{C}} S_T, \ \text{ties to the lower } C_T \\ &6\;\; \mathcal{C} = \varnothing \Rightarrow \text{no fit: report the nearest by cost and the excluding rule of each; never relax a rule} \end{aligned} \]
done whenThree real contexts are profiled by municipal staff through the form, assessed and closed, with the protocol revised from what the pilot found.
On the live system · evidence tiers, and the floor that refuses a closing
Left: a monitored site whose variables were recorded on a site visit, the tier select on every row reading
Left: a monitored site whose variables were recorded on a site visit, the tier select on every row reading
Left: a monitored site whose variables were recorded on a site visit, the tier select on every row reading
Left: a monitored site whose variables were recorded on a site visit, the tier select on every row reading "visit". Right: on Suitability the same site is assessed on the pick and refused by the evidence floor, which names the measurements below it; the planner accepts them with the switch and runs, or completes the survey.

E · Validation

metrics defined · run on assumed contexts

Three checks in order, each deterministic, and the paper reports their results rather than asserting the method works.

ReproduceSection A's test, recorded.
Back-test the eight de-risked sitesTheir contexts built from the site reports plus the measurements the reports lack. The installed system's class must survive the gates; a failure is a defect in a rule or a context and is listed and fixed at that level. The conditions the method raises are compared with each site's HAZOP categories and the overlap reported. Ekuthuleni first: the method should raise front-end robustness and consumables provisioning, because the field did.
Discrepancy against outcomesInfraTrack's uptime and time within specification, grouped by class and context band, set against the operating-risk scores of section B. The first release shows the gap and an engineer adjusts the register with the evidence in front of them. Nothing adjusts itself.
What stays provisionalThe paper's closing section lists, by class, which scores rest on a monitored site and which on reasoning, and which costs are computable at publication.

Model · the three checks as metrics, and a run on assumed contexts

Coverage is a count \(D\) of component, criterion and band triples a context can present that have no rule in the register, with tolerance zero sourced. Result: \(D = 0\) over \(309\) rules. The back-test has two numbers per site. Survival is whether the installed system passes the screen for the site's context. Overlap is the Jaccard similarity between the set \(R\) of categories of the conditions the method raises, from the rule conditions of the screen and from any operating-risk criterion of the class at or below the watch threshold \(\omega = 0.5\) assumed, and the set \(H\) of hazard-register categories the site recorded. Design and process entries are commissioning matters the screen never raises, so a second overlap is computed over the selection-relevant categories \(\mathcal{S} = \{\text{front end}, \text{O\&M}, \text{data}\}\).

\[ J = \frac{|R \cap H|}{|R \cup H|}, \qquad J_{\mathcal S} = \frac{|(R\cap\mathcal S) \cap (H\cap\mathcal S)|}{|(R\cap\mathcal S) \cup (H\cap\mathcal S)|} \]

The discrepancy report maps observed performance \(u\), percentage uptime or time within specification, to the same four bands the register uses, with cut points \(90\), \(75\) and \(50\) assumed, and flags a class whose register score differs from its observed band by \(\theta = 0.25\) or more assumed. An engineer changes the register. Nothing changes itself.

\[ b(u) = \begin{cases} 1.00 & u \ge 90 \\ 0.75 & 75 \le u < 90 \\ 0.50 & 50 \le u < 75 \\ 0.25 & u < 50 \end{cases}, \qquad \text{flag} \iff |q_{c,i} - b(u)| \ge \theta \]

First run of the back-test on the five sites with hazard registers, each context built from the two or three measurements the site report gives and thirteen or fourteen assumptions that the baseline visit replaces:

SiteInstalledSurvivesKnown / assumed\(R\)\(H\)\(J\) / \(J_{\mathcal S}\)
PHOCommunal WESSyes2 / 11O&M, front enddesign, process0.0 / 0.0
EKUCommunal WESSyes2 / 11O&M, front endO&M, design, front end, process0.5 / 1.0
OAKRecirculating unityes1 / 12O&M, front endfront end0.5 / 0.5
JOBRecirculating unityes2 / 11O&M, front endO&M, design, front end0.67 / 1.0
MALCommunal WESSyes3 / 10O&M, front endO&M, data, design, process0.2 / 0.33

The run does what the check is for. All five installed systems survive, Ekuthuleni with a condition: its assumed water supply, a communal standpipe, makes top-up water for the recirculating units an obligation under the installation requirement of ISO 30500 rather than a failure, and the pilot measurement decides whether the assumption holds. Where the record holds selection-relevant categories, the method raises them: Nooitgedacht and Ekuthuleni at \(J_{\mathcal S} = 1\), Oakford at \(0.5\) because the method also raises operations and maintenance where the record shows only the front end. Upper Malacca's data-and-reporting entry is the one selection-relevant category the method missed, and its telemetry score for the class is \(0.75\), above the watch threshold, so the threshold or the score is the parameter to revisit. Every number here rests on assumed measurements and is replaced by the pilot's.

done whenAll eight installed systems survive the back-test, or each failure is explained and fixed at the rule or context, and the discrepancy view renders on real InfraTrack data.
On the live system · the three checks on the Register tab
The back-test over the five monitored sites (installed system survives its own site; conditions raised against the hazard categories recorded), the discrepancy report of the register's operating-risk scores against the observed record per class with the flagged criteria, and the picked site's raised conditions beside what its hazard register recorded. Nothing recalibrates itself; the engineer edits the register.
The back-test over the five monitored sites (installed system survives its own site; conditions raised against the hazard categories recorded), the discrepancy report of the register's operating-risk scores against the observed record per class with the flagged criteria, and the picked site's raised conditions beside what its hazard register recorded. Nothing recalibrates itself; the engineer edits the register.
The back-test over the five monitored sites (installed system survives its own site; conditions raised against the hazard categories recorded), the discrepancy report of the register's operating-risk scores against the observed record per class with the flagged criteria, and the picked site's raised conditions beside what its hazard register recorded. Nothing recalibrates itself; the engineer edits the register.
The back-test over the five monitored sites (installed system survives its own site; conditions raised against the hazard categories recorded), the discrepancy report of the register's operating-risk scores against the observed record per class with the flagged criteria, and the picked site's raised conditions beside what its hazard register recorded. Nothing recalibrates itself; the engineer edits the register.
The back-test over the five monitored sites (installed system survives its own site; conditions raised against the hazard categories recorded), the discrepancy report of the register's operating-risk scores against the observed record per class with the flagged criteria, and the picked site's raised conditions beside what its hazard register recorded. Nothing recalibrates itself; the engineer edits the register.
Definitions

Variables

Every symbol used in the models, in the order the path uses them. A symbol means one thing throughout. Where the white paper used \(\rho\) for both the discount rate and the operating-risk score, the score is now \(q\).

Table 7 · Variables of the method
SymbolMeaningUnit
Screen and ranking
\(T\)a system: a chain of components; \(|T|\) its length–
\(k\)a component of a chain (a Compendium code, or a CEN code for a component of the Centre's)–
\(i, \ I\)a criterion; the set of twelve scoring criteria–
\(v_{k,i},\ v_{T,i}\)the verdict of a component, and of a system, on a gate criterion: pass, conditional or fail, with fail below conditional below passordinal
\(f_{T,i}\)the register value of a system on construction ease, space, further treatment, reuse or water requiredunit interval
\(\kappa_k,\ \kappa_o\)the reference capital and twenty-year operating cost at which the cost criteria score zeroR per household
\(c(T)\)the class of a system: dry, non-sewered water-based, WESS, sewered central, sewered decentralised–
\(q_{c,i}\)the operating-risk score of class \(c\) on criterion \(i\)unit interval
\(n\)hazard-register entries in a category per site (per site-year once known)count
\(c_1, c_2\)the cut points of the operating-risk band function \(q(n)\)entries per site
\(s_{T,i}\)the score of a system on a criterionunit interval
\(w_i\)the base weight of a criterionpoints, sum 100
\(g_i,\ \gamma\)the goal factor on a criterion; its value when a selected goal touches the criterionmultiplier
\(S_T\)the fit score of a system0 to 100
\(\varepsilon\)the weight perturbation of the stability testfraction
\(Z,\ \sigma\)the set of test contexts; the stability indexfraction
Cost
\(k\)capital per household (a communal unit's \(K_{ ext{unit}}\) divided by \(N\))R
\(o,\ c,\ e\)operating, consumables and energy cost per household per yearR per year
\(\tau,\ p_e\)the desludging or collection interval; the cost per event per householdyears; R
\(L,\ p_r\)the route length one way (a context measurement); the route cost per kilometre per householdkm; R per km
\(\tau_r,\ \varphi\)the refurbishment interval; the fraction of capital spent at each refurbishmentyears; fraction
\(N\)the households a communal unit serveshouseholds
\(\rho,\ H\)the discount rate the planner enters; the horizonper year; years
\(d_y,\ r_y,\ n_y\)desludging and refurbishment outlay in year \(y\); events in year \(y\)R; R; count
\(C_T\)the twenty-year cost per household of a system, a present valueR
\(\beta\)the capital envelope per household the strategy allowsR
Survey and closing
\(m,\ t(m)\)a measurement of the sixteen; its source tier: record, visit, field test or engagement–
\(h_t\)staff hours a tier implies per measurementhours
\(E_z,\ \text{cost}_z\)the effort and cost of profiling a zonehours; R
\(\mathcal{C},\ T^\star\)the candidate set of the closing algorithm; the recommendation–
Validation
\(D\)component, criterion and band triples a context can present that have no rule (coverage)count
\(R,\ H\)the categories of conditions the method raises; the categories the site's hazard register holdssets
\(\mathcal{S}\)the selection-relevant categories: front end, operations and maintenance, dataset
\(J,\ J_{\mathcal S}\)the overlap of \(R\) and \(H\), over all categories and over \(\mathcal S\)Jaccard, 0 to 1
\(\omega\)the watch threshold: an operating-risk score at or below it raises a conditionunit interval
\(u,\ b(u)\)observed uptime or time within specification; its bandpercent; unit interval
\(\theta\)the recalibration trigger on \(|q_{c,i} - b(u)|\)unit interval
Register

Values

Every parameter the models read, with its value at publication and a grade of how defensible that value is. The grade is separate from the status badge: a badge says whether a document supplies the value, the grade says how far the value can be defended today and what replaces it. There are \(186\) parameters, and the work that raises each grade is listed by section, including the work still owed on the sourced ones.

Table 8 · The four grades
GradeMeaningParameters
Asourced from a named document\(19\)
Bderived from sourced figures by stated arithmetic\(1\)
Ca bounded assumption, within a range known from practice or the literature, with a named replacement\(86\)
Da placeholder of the right order of magnitude, present so the model computes\(80\)
Table 9 · Confidence work, by section
SectionWhat is done, and what is planned, to develop confidence
B · RankingThe 24 hazard entries are re-categorised at sign-off and normalised per site-year as monitoring periods close. The band cut points and the four provisional class scores are tested by the discrepancy report each quarter against uptime and time within specification. The weights carry a sentence each and are swept at \(\pm 20\) and \(\pm 50\) percent, the second sweep to find where the ranking does move. The per-system register values are replaced by field-record values as a monitored site of each class closes.
C · Cost, globalThe discount rate is never defaulted: the planner enters the municipality's capital planning rate and both illustrative rates are re-run. The route length becomes a measured distance per zone from the GIS layer. The residual-value assumption is tested by re-running at a 20 percent residual on the sewered class, where it matters most.
C · Cost, per systemA hand-computed present value at both rates must match the table (the model's own test). Every placeholder is replaced by a document: provider quotations on the de-risked sites for the WESS class, eThekwini reticulation and works unit rates and the cost per kilolitre treated for the sewered class, DEWATS and packaged-plant quotations for the decentralised class, and the Sanitation Operations Branch contract rates for urine-diversion and pit emptying and the ablution-block programme's capital and caretaker costs for the dry and NSS classes. Until then each value is checked for order of magnitude against the cost review of Daudey (2018) and the costing categories of Sainati and colleagues (2020), and the whole table is re-run whenever one row changes. Even the two sourced intervals are checked against the emptying records for the intervals actually achieved.
D · Survey and closingHours and day rates are timed in the October pilot on three zones and the protocol is republished in the form the pilot leaves it. The evidence floor is tested by attempting to close an assessment with one gate measurement below it, which must be refused.
E · ValidationThe watch threshold and the category map are tested on the eight de-risked sites once their contexts are measured, Upper Malacca's missed data category first. The discrepancy bands and trigger are exercised on the first quarter of monitored uptime, and any change to a class score is made by an engineer with the evidence recorded beside it.
Table 10 · The full register: value, unit, grade, basis\(186\) rows, generated from tools/parameters.py. Edit the source, never this table
ParameterValueUnitGradeBasis
B · Ranking
systemFit{"VIP with FSM": {"constructionEase": 1.0, "furtherTreatment": 0.33, "reuse": 0.33, "water…unit intervalCCOMP technology sheets (construction, operation, applicability and products), ISO 30500 for the water-efficient class, the works register for the sewered class; class-level statements graded C until the field record supplies them
goalFactor\(2\)multiplierCa selected goal doubles the weight of the criteria it touches
riskBandCutPoints[0.5, 1.0]HAZOP entries per siteCscore 1.0 none · 0.75 up to 0.5 per site · 0.5 up to 1.0 per site · 0.25 above; per site-year once the monitored period is known
riskBandScores[1.0, 0.75, 0.5, 0.25]unit intervalCthe four bands, best to worst
perturbation\(0.2\)fraction of each weightCa fifth up and down on every weight in turn
stabilityFloor\(0.7778\)fraction of contextsCthe top rank must hold in at least seven of nine contexts
weights{"capital": 12, "operational": 12, "constructionEase": 6, "space": 8, "furtherTreatment": …points, sum 100Ctables/operating-risk-scores.md section 3, one sentence each; owner sign-off pending
operatingRisk{"wess": {"frontEnd": 0.25, "consumables": 0.75, "desludging": 0.75, "skill": 0.5, "teleme…unit intervalBWESS column from the 24 HAZOP entries (sourced); the other four classes from the class definition, provisional
C · Cost, global
horizon\(20\)yearsAthe twenty-year window of the method
discountRates[0.06, 0.1]per yearCtwo illustrative rates for the hand-check; the planner enters the municipality's own rate and there is no default in the tool
routeKm\(20\)km, one wayCcontext measurement: distance from the settlement to the disposal or treatment point
residualValue\(0\)fraction of capital at year 20Cno residual value credited
costReference{"capital": 45000, "operating": 90000}R per householdCthe cost at which the capital and operating fit criteria score zero: the catalogue's highest capital (conventional sewer) and twice it for the twenty-year non-capital present value; a cost of zero scores one, linear between
C · Cost: VIP with FSM
capital\(12{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation
opex\(200\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(0\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(0\)R per household per yearDelectricity or solar replacement cost
interval\(5\)years between desludging or collection events (0 = none)AeThekwini Service Level Standards, 18th ed. (2024): pit emptying every five years
eventCost\(2{,}500\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(25\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(10\)yearsCservice life of the wearing components
refurbFraction\(0.3\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: UDDT
capital\(16{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation
opex\(300\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(0\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(0\)R per household per yearDelectricity or solar replacement cost
interval\(2\)years between desludging or collection events (0 = none)AeThekwini Service Level Standards, 18th ed. (2024): urine-diversion emptying every two years
eventCost\(900\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(25\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(10\)yearsCservice life of the wearing components
refurbFraction\(0.25\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: Composting
capital\(14{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation
opex\(400\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(100\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(0\)R per household per yearDelectricity or solar replacement cost
interval\(1\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(600\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(25\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(10\)yearsCservice life of the wearing components
refurbFraction\(0.3\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: Container-based
capital\(6{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation; collection weekly within the service fee
opex\(600\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(300\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(0\)R per household per yearDelectricity or solar replacement cost
interval\(0.0192\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(60\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(0\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(5\)yearsCservice life of the wearing components
refurbFraction\(0.5\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: Pour-flush twin pits
capital\(14{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation
opex\(250\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(0\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(0\)R per household per yearDelectricity or solar replacement cost
interval\(3\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(2{,}000\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(25\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(15\)yearsCservice life of the wearing components
refurbFraction\(0.2\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: Septic + soakaway
capital\(35{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation
opex\(400\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(0\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(0\)R per household per yearDelectricity or solar replacement cost
interval\(3\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(2{,}500\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(25\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(15\)yearsCservice life of the wearing components
refurbFraction\(0.25\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: Conservancy tank
capital\(30{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation; emptied monthly
opex\(400\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(0\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(0\)R per household per yearDelectricity or solar replacement cost
interval\(0.0833\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(1{,}800\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(25\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(15\)yearsCservice life of the wearing components
refurbFraction\(0.2\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: Recirculating unit
capital\(45{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation; household WESS unit
opex\(1{,}200\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(1{,}500\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(600\)R per household per yearDelectricity or solar replacement cost
interval\(2\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(2{,}500\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(25\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(7\)yearsCservice life of the wearing components
refurbFraction\(0.35\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: Communal WESS
capital\(16{,}667\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation; one communal unit of R2.0m serving 120 households; unit desludged yearly at R4,000
opex\(500\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(200\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(125\)R per household per yearDelectricity or solar replacement cost
interval\(1\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(33.33\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(0.208\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(7\)yearsCservice life of the wearing components
refurbFraction\(0.35\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(120\)householdsCcommunal unit service population
C · Cost: Settled sewerage
capital\(38{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation; interceptor tank, solids-free sewer and a DEWATS share
opex\(900\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(0\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(100\)R per household per yearDelectricity or solar replacement cost
interval\(3\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(2{,}500\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(25\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(20\)yearsCservice life of the wearing components
refurbFraction\(0.3\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: DEWATS
capital\(28{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation
opex\(600\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(0\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(0\)R per household per yearDelectricity or solar replacement cost
interval\(2\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(3{,}000\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(25\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(10\)yearsCservice life of the wearing components
refurbFraction\(0.3\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: Packaged plant (settlement)
capital\(32{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation
opex\(1{,}500\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(400\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(900\)R per household per yearDelectricity or solar replacement cost
interval\(1\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(3{,}500\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(25\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(8\)yearsCservice life of the wearing components
refurbFraction\(0.4\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: Simplified sewer to works
capital\(30{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation; reticulation plus a works share; treatment cost recovered through the tariff
opex\(700\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(0\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(150\)R per household per yearDelectricity or solar replacement cost
interval\(0\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(0\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(0\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(25\)yearsCservice life of the wearing components
refurbFraction\(0.3\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: Conventional sewer to works
capital\(45{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation; reticulation plus a works share
opex\(800\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(0\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(150\)R per household per yearDelectricity or solar replacement cost
interval\(0\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(0\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(0\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(30\)yearsCservice life of the wearing components
refurbFraction\(0.3\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(1\)householdsAhousehold system
C · Cost: CAB on sewer
capital\(26{,}667\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation; one block of R2.0m serving 75 households, a caretaker at R120,000 a year
opex\(1{,}600\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(200\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(80\)R per household per yearDelectricity or solar replacement cost
interval\(0\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(0\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(0\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(8\)yearsCservice life of the wearing components
refurbFraction\(0.4\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(75\)householdsCcommunal unit service population
C · Cost: CAB on septic
capital\(28{,}000\)R per householdDplanning assumption at 2026 prices, order of magnitude; replace with the contract rate or quotation; the block on a septic tank emptied quarterly at R2,500
opex\(1{,}600\)R per household per yearDlabour and repairs; excludes consumables and energy
consumables\(200\)R per household per yearDchemicals, media, paper, cleaning agents
energy\(80\)R per household per yearDelectricity or solar replacement cost
interval\(0.25\)years between desludging or collection events (0 = none)Cplanning assumption
eventCost\(33.33\)R per event per householdDcontractor rate per emptying or collection
routeCostPerKm\(0.333\)R per km per event per householdCvehicle running cost, shared by the households a unit serves; the route length is a context measurement
refurbInterval\(8\)yearsCservice life of the wearing components
refurbFraction\(0.4\)fraction of capitalCshare of capital spent at each refurbishment
householdsPerUnit\(75\)householdsCcommunal unit service population
D · Survey and closing
tiers{"record": "GIS, billing, works register, flood lines, settlement register", "visit": "sit…source tierAAppendix A of the white paper
hoursPerMeasurement{"record": 0.5, "visit": 0.75, "field test": 3.0, "engagement": 2.0}hoursCstaff time per measurement by tier, timed in the pilot
dayRate{"technician": 2800, "engineer": 6500}R per dayCmunicipal cost-to-company day rates; replace with the municipality's own
zoneCostEstimate\(15{,}000\)R per zoneCCentre estimate: two site-visit days, a percolation test, GIS and record extraction, the assessment (Research-Notes-EWS-Plan)
evidenceFloor{"gate": "record or field test", "score": "record, visit or engagement", "derived": "input…minimum tierCa gate measurement may not close an assessment from an assumption
closingRule["candidates = survivors minus systems the policy layer excludes for the upgrading categor…ruleAprinted verbatim in the method
E · Validation
ruleCoverage\(1\)fraction of (component, criterion, band) triplesAevery triple a context can present has a rule in the register; a gap is an error, never a pass
conditionCategories{"front end": ["frontEnd"], "O&M": ["consumables", "desludging", "skill"], "data": ["telem…mapCwhich operating-risk criteria correspond to which HAZOP category; design and process are not selection conditions
watchThreshold\(0.5\)unit intervalCan operating-risk score at or below this raises a watch condition for the class
overlapMetricJaccardset similarityCraised condition categories against HAZOP categories recorded, per site
discrepancyBands[90, 75, 50]percent uptime or time within specificationCobserved performance mapped to the four risk bands: above 90 = 1.0, 75 to 90 = 0.75, 50 to 75 = 0.5, below 50 = 0.25
recalibrationTrigger\(0.25\)absolute score differenceCa class score differing from its observed band by this much is flagged for an engineer; nothing adjusts itself
Closing envelope
budgetCap (\(\beta\))\(30{,}000\)R capital per householdCa working envelope per household; the plan's R1 to 2 billion over 225,799 B1 households is R4,400 to R8,900
Illustration

Case studies under the assumed values

Three archetypes of the incremental-upgrading register, each run through the whole path with every parameter at its register value: the screen with its deciding rules, the municipal policy layer, fit beside cost, and the closing algorithm to one recommendation. The zones are types, not named settlements, and every measurement is an assumption of the kind the survey replaces. What the runs show is the machinery: which rule eliminates what, where the policy layer bites, how far fit and cost disagree, and what the envelope removes. Read with the values section open.

Z1 · Dense B1 settlement beyond sewer reach

B1 · \(1{,}200\) households · goals: lowCost, minimalOM

A settlement of the kind that dominates the register: very high density on public standpipes, low water availability, a shallow water table over sandy clay, peripheral vehicle access, more than a kilometre from a main sewer and no works with headroom within reach.

Context, every measurement assumed
projectTypeCommunal
toiletLocationOutside dwelling
waterTypeCommunal standpipes: Piped water connection for public use
waterAmountLow (10-25 litres/person/day)
floodProneNo
soilSandy Clay
waterTableDepth2-5 metres
housingDensityVery High: >300 HHs per hectare
percolation15 - 25 mm/hour
accessPeripheral access - access to the periphery of the area
terrain<25°
sewerDistance>1000 metres
wwtpCapacityNo
Eliminated, with the deciding rule
  • VIP with FSM: S3 on housingDensity (COMP S.3: space for the pit and for a replacement pit; density cut points a planning assumption to confirm with EWS)
  • Pour-flush twin pits: S6 on housingDensity (COMP S.3: space for the pit and for a replacement pit; density cut points a planning assumption to confirm with EWS)
  • Septic + soakaway: U5 on waterType (COMP U.5: a cistern needs a piped supply); U5 on waterAmount (COMP U.5: 6 to 9 litres a flush cannot be met below 25 litres a person a day); S9 on housingDensity (COMP S.9: a tank and its soak pit need plot area a dense settlement lacks); D7 on housingDensity (COMP D.7: not for dense settlements)
  • Conservancy tank: U5 on waterType (COMP U.5: a cistern needs a piped supply); U5 on waterAmount (COMP U.5: 6 to 9 litres a flush cannot be met below 25 litres a person a day)
  • Settled sewerage: U5 on waterType (COMP U.5: a cistern needs a piped supply); U5 on waterAmount (COMP U.5: 6 to 9 litres a flush cannot be met below 25 litres a person a day); S9 on housingDensity (COMP S.9: a tank and its soak pit need plot area a dense settlement lacks)
  • DEWATS: U5 on waterType (COMP U.5: a cistern needs a piped supply); U5 on waterAmount (COMP U.5: 6 to 9 litres a flush cannot be met below 25 litres a person a day)
  • Packaged plant (settlement): U5 on waterType (COMP U.5: a cistern needs a piped supply); U5 on waterAmount (COMP U.5: 6 to 9 litres a flush cannot be met below 25 litres a person a day)
  • Simplified sewer to works: U5 on waterType (COMP U.5: a cistern needs a piped supply); U5 on waterAmount (COMP U.5: 6 to 9 litres a flush cannot be met below 25 litres a person a day); CEN-T-WORKS on sewerDistance (planning assumption: 1000 m economic connection distance to the main sewer, to be confirmed with EWS (the SLS states none)); CEN-T-WORKS on worksHeadroom (GD: a works at or over design capacity, or in the critical risk class, may not take new connections)
  • Conventional sewer to works: U5 on waterType (COMP U.5: a cistern needs a piped supply); U5 on waterAmount (COMP U.5: 6 to 9 litres a flush cannot be met below 25 litres a person a day); CEN-T-WORKS on sewerDistance (planning assumption: 1000 m economic connection distance to the main sewer, to be confirmed with EWS (the SLS states none)); CEN-T-WORKS on worksHeadroom (GD: a works at or over design capacity, or in the critical risk class, may not take new connections)
  • CAB on sewer: U5 on waterType (COMP U.5: a cistern needs a piped supply); U5 on waterAmount (COMP U.5: 6 to 9 litres a flush cannot be met below 25 litres a person a day); CEN-T-WORKS on sewerDistance (planning assumption: 1000 m economic connection distance to the main sewer, to be confirmed with EWS (the SLS states none)); CEN-T-WORKS on worksHeadroom (GD: a works at or over design capacity, or in the critical risk class, may not take new connections)
  • CAB on septic: U5 on waterType (COMP U.5: a cistern needs a piped supply); U5 on waterAmount (COMP U.5: 6 to 9 litres a flush cannot be met below 25 litres a person a day); S9 on housingDensity (COMP S.9: a tank and its soak pit need plot area a dense settlement lacks); D7 on housingDensity (COMP D.7: not for dense settlements)
Excluded by the policy layer
  • none
Survivors, ranked on fit beside cost
System\(S_T\)\(C_T\), \(\rho = 0.06\)\(k\)Conditions
UDDT\(70.2\)\(32{,}254\)\(16{,}000\)\(2\)
Composting\(68.3\)\(40{,}432\)\(14{,}000\)\(1\)
Communal WESS\(65.9\)\(33{,}067\)\(16{,}667\)\(2\)
Container-based\(65.4\)\(57{,}278\)\(6{,}000\)\(0\)
Recirculating unit\(46.8\)\(119{,}779\)\(45{,}000\)\(3\)
Closing
  1. candidates: 5 survivors after the policy layer (0 excluded by policy)
  2. conditions: all accepted for the case study, responsible party the municipality; none dropped
  3. budget envelope R30,000 capital per household: dropped Recirculating unit
  4. every remaining cost rests on assumed parameters; the assumption list is accepted as a named condition for the case study
  5. highest fit: UDDT at 70.2
recommendationUDDT, at fit \(70.2\) and \(\mathrm{R}\,32{,}254\) over twenty years
On the live system · Z1 closed under P1
The verdict chips and the closing trail for Z1 as the system computes them from the same register: five survivors, none excluded by policy, conditions accepted with the municipality responsible, the envelope applied, the highest fit chosen.
The verdict chips and the closing trail for Z1 as the system computes them from the same register: five survivors, none excluded by policy, conditions accepted with the municipality responsible, the envelope applied, the highest fit chosen.
The verdict chips and the closing trail for Z1 as the system computes them from the same register: five survivors, none excluded by policy, conditions accepted with the municipality responsible, the envelope applied, the highest fit chosen.

Z2 · Peri-urban B1 zone on yard taps, on-site service

B1 · \(400\) households · goals: waterSensitive, lowCost

Medium density on yard taps with medium water availability, sandy loam over a water table at five to ten metres, partial vehicle access, no sewer within a kilometre.

Context, every measurement assumed
projectTypeHousehold
toiletLocationOutside dwelling
waterTypeYard tap: Single tap provided in each plot
waterAmountMedium (25-60 litres/person/day)
floodProneNo
soilSandy Loam
waterTableDepth5-10 metres
housingDensityMedium: 50-150 HHs per hectare
percolation25 - 100 mm/hour
accessPartial access - Access to several households in the area
terrain<25°
sewerDistance>1000 metres
wwtpCapacityNo
Eliminated, with the deciding rule
  • Communal WESS: CEN-T-WESS-COM on projectType (FR: a communal train serves a shared block)
  • Simplified sewer to works: CEN-T-WORKS on sewerDistance (planning assumption: 1000 m economic connection distance to the main sewer, to be confirmed with EWS (the SLS states none)); CEN-T-WORKS on worksHeadroom (GD: a works at or over design capacity, or in the critical risk class, may not take new connections)
  • Conventional sewer to works: CEN-T-WORKS on sewerDistance (planning assumption: 1000 m economic connection distance to the main sewer, to be confirmed with EWS (the SLS states none)); CEN-T-WORKS on worksHeadroom (GD: a works at or over design capacity, or in the critical risk class, may not take new connections)
  • CAB on sewer: CEN-T-WORKS on sewerDistance (planning assumption: 1000 m economic connection distance to the main sewer, to be confirmed with EWS (the SLS states none)); CEN-T-WORKS on worksHeadroom (GD: a works at or over design capacity, or in the critical risk class, may not take new connections)
Excluded by the policy layer
  • VIP with FSM: no new ventilated pits
Survivors, ranked on fit beside cost
System\(S_T\)\(C_T\), \(\rho = 0.06\)\(k\)Conditions
UDDT\(73.3\)\(32{,}254\)\(16{,}000\)\(0\)
Composting\(71.9\)\(40{,}432\)\(14{,}000\)\(0\)
Container-based\(70.8\)\(57{,}278\)\(6{,}000\)\(0\)
Pour-flush twin pits\(65.1\)\(28{,}239\)\(14{,}000\)\(1\)
DEWATS\(52.8\)\(61{,}844\)\(28{,}000\)\(2\)
Recirculating unit\(49.9\)\(119{,}779\)\(45{,}000\)\(0\)
Settled sewerage\(48.7\)\(61{,}374\)\(38{,}000\)\(2\)
CAB on septic\(48.5\)\(63{,}140\)\(28{,}000\)\(2\)
Septic + soakaway\(45.9\)\(55{,}143\)\(35{,}000\)\(2\)
Packaged plant (settlement)\(45.1\)\(128{,}800\)\(32{,}000\)\(2\)
Conservancy tank\(39.0\)\(422{,}481\)\(30{,}000\)\(2\)
Closing
  1. candidates: 11 survivors after the policy layer (1 excluded by policy)
  2. conditions: all accepted for the case study, responsible party the municipality; none dropped
  3. budget envelope R30,000 capital per household: dropped Recirculating unit, Settled sewerage, Septic + soakaway, Packaged plant (settlement)
  4. every remaining cost rests on assumed parameters; the assumption list is accepted as a named condition for the case study
  5. highest fit: UDDT at 73.3
recommendationUDDT, at fit \(73.3\) and \(\mathrm{R}\,32{,}254\) over twenty years
On the live system · Z2 closed under P1
Z2 on yard taps with on-site service: eleven survivors after the policy layer, and the closing trail naming what the envelope removed.
Z2 on yard taps with on-site service: eleven survivors after the policy layer, and the closing trail naming what the envelope removed.
Z2 on yard taps with on-site service: eleven survivors after the policy layer, and the closing trail naming what the envelope removed.

Z3 · B1 settlement within the catchment of a works with headroom

B1 · \(800\) households · goals: lowCost

High density on metered house connections, loam over a deep water table, full vehicle access, a main sewer within a kilometre and a low-risk works with headroom (Northern) as the receiving works.

Context, every measurement assumed
projectTypeHousehold
toiletLocationEither inside or outside
waterTypeHousehold connection: Metered connection into the house.
waterAmountMedium high (60-100 litres/person/day)
floodProneNo
soilLoam
waterTableDepth>10 metres
housingDensityHigh: 150-300 HHs per hectare
percolation25 - 100 mm/hour
accessFull access - access to all households inside the area
terrain<25°
sewerDistance<1000 metres
wwtpCapacityYes
Eliminated, with the deciding rule
  • Communal WESS: CEN-T-WESS-COM on projectType (FR: a communal train serves a shared block)
Excluded by the policy layer
  • VIP with FSM: no new ventilated pits
  • UDDT: no urine diversion at metered premises
Survivors, ranked on fit beside cost
System\(S_T\)\(C_T\), \(\rho = 0.06\)\(k\)Conditions
Composting\(69.9\)\(40{,}432\)\(14{,}000\)\(0\)
Container-based\(68.7\)\(57{,}278\)\(6{,}000\)\(0\)
Simplified sewer to works\(65.5\)\(39{,}749\)\(30{,}000\)\(0\)
Pour-flush twin pits\(65.0\)\(28{,}239\)\(14{,}000\)\(1\)
CAB on sewer\(64.3\)\(59{,}122\)\(26{,}667\)\(0\)
Conventional sewer to works\(57.3\)\(55{,}896\)\(45{,}000\)\(0\)
DEWATS\(54.2\)\(61{,}844\)\(28{,}000\)\(0\)
Settled sewerage\(49.8\)\(61{,}374\)\(38{,}000\)\(1\)
CAB on septic\(49.6\)\(63{,}140\)\(28{,}000\)\(1\)
Recirculating unit\(47.6\)\(119{,}779\)\(45{,}000\)\(0\)
Septic + soakaway\(46.8\)\(55{,}143\)\(35{,}000\)\(1\)
Packaged plant (settlement)\(45.9\)\(128{,}800\)\(32{,}000\)\(0\)
Conservancy tank\(39.4\)\(422{,}481\)\(30{,}000\)\(0\)
Closing
  1. candidates: 13 survivors after the policy layer (2 excluded by policy)
  2. conditions: all accepted for the case study, responsible party the municipality; none dropped
  3. budget envelope R30,000 capital per household: dropped Conventional sewer to works, Settled sewerage, Recirculating unit, Septic + soakaway, Packaged plant (settlement)
  4. every remaining cost rests on assumed parameters; the assumption list is accepted as a named condition for the case study
  5. highest fit: Composting at 69.9
recommendationComposting, at fit \(69.9\) and \(\mathrm{R}\,40{,}432\) over twenty years
On the live system · Z3 closed under P1
Z3 inside the catchment of a works with headroom: the sewered systems survive the screen, and the closing under the draft policy still chooses Composting on fit; under the operations-first policy the same site closes to a simplified sewer (see Policies).
Z3 inside the catchment of a works with headroom: the sewered systems survive the screen, and the closing under the draft policy still chooses Composting on fit; under the operations-first policy the same site closes to a simplified sewer (see Policies).
Z3 inside the catchment of a works with headroom: the sewered systems survive the screen, and the closing under the draft policy still chooses Composting on fit; under the operations-first policy the same site closes to a simplified sewer (see Policies).

Three observations, about the method rather than the settlements. In the dense zone the screen alone removes thirteen of sixteen systems, most on the water gate and the pit-vulnerability gate, and the ranking is among three dry systems, so the decision there is a dry-class decision whatever the weights. In the peri-urban zone the policy layer removes the ventilated pit that the screen admitted, and the envelope of \(\mathrm{R}\,30{,}000\) removes the household water-efficient unit at \(\mathrm{R}\,45{,}000\) capital, so the recommendation follows from two rules a reader can point to. In the sewered-reach zone the highest fit is the container-based system at \(69.9\) while the simplified sewer connection at \(65.5\) costs \(\mathrm{R}\,39{,}749\) against \(\mathrm{R}\,40{,}432\) over twenty years. The closing rule takes fit, and the record shows the planner the \(\mathrm{R}\,683\) that the choice forgoes, which is the trade the two-column display exists to expose. Whether the container-based system should outrank a sewer connection where a works has headroom is a question for the weights and the operating-risk scores at sign-off, and the case study is the evidence for that conversation.

The arithmetic of the envelope deserves its own line. The ten-year plan's \(\mathrm{R}\,1\) to \(\mathrm{R}\,2\) billion for underserved-community sanitation over the \(225{,}799\) households in incremental upgrading is \(\mathrm{R}\,4{,}400\) to \(\mathrm{R}\,8{,}900\) per household, below the capital of every system in the catalogue. The strategy layer is where that is confronted: phasing, the count of households actually reached in the window, and the classes whose capital sits nearest the envelope.

Desirability

Policies: what makes one system more desirable than another

The fit score and the closing rule encode a view of what a municipality wants, and that view is a decision the municipality makes rather than a property of the method. The method therefore treats desirability as a named policy, and a recommendation is optimal relative to a policy. Two municipalities with the same catalogue and the same rules can hold different policies and receive different recommendations for the same zone, each with its reasoning, and one municipality can compare its own policy against alternatives before adopting it.

A policy \(\pi\) declares seven things: the base weights \(w_i^{\pi}\), the goal factor \(\gamma^{\pi}\), the goals \(G^{\pi}\) it forces on every zone, the exclusion rules \(X^{\pi}\) drawn from the municipality's own policy documents, the capital envelope \(\beta^{\pi}\), the margin \(\delta^{\pi}\) within which the cheaper of two near-equal systems is preferred, and the discount rate \(\rho^{\pi}\) it costs at. The screen is not part of a policy: a system that cannot work in a context cannot be made desirable.

Model · fit and closing under a policy, and alignment between policies

\[ S_T^{\pi} = 100\,\frac{\sum_i w_i^{\pi}\, g_i^{\pi}\, s_{T,i}}{\sum_i w_i^{\pi}\, g_i^{\pi}}, \qquad g_i^{\pi} = \begin{cases} \gamma^{\pi} & i \text{ touched by a goal in } G^{\pi} \cup G_z \\ 1 & \text{otherwise} \end{cases} \]
\[ \mathcal{C}^{\pi}_z = \{T : v_{T}(z) \ne \text{fail},\ T \notin X^{\pi}(z),\ \text{conditions accepted},\ k_T \le \beta^{\pi},\ C_T \text{ computable}\} \]
\[ \mathcal{N} = \{T \in \mathcal{C}^{\pi}_z : S_T^{\pi} \ge \max_{T'} S_{T'}^{\pi} - \delta^{\pi}\}, \qquad T^{\star}_{\pi}(z) = \arg\min_{T \in \mathcal{N}} C_T \]

With \(\delta^{\pi} = 0\) the rule is strict fit with cost as tie-break, which is the closing rule of section D. With \(\delta^{\pi} > 0\) cost decides among systems the policy regards as near-equal on fit. The alignment of two policies over a set of zones \(Z\) is the share of zones on which they recommend the same system:

\[ A(\pi, \pi') = \frac{1}{|Z|} \sum_{z \in Z} \mathbf{1}\big[T^{\star}_{\pi}(z) = T^{\star}_{\pi'}(z)\big] \]

Four policies are registered, every one assumed. The first, the municipality's draft policy read as exclusion clauses with the register's weights, is the working default; the other three are the comparisons a planner puts beside it.

PolicyWeights that differ from the registerGoals forcedExclusions\(\beta\)\(\delta\)
P1 eThekwini draft policy (2025)the register weights–no new ventilated pits; no urine diversion at metered premises; B2 and C settlements: interim systems only\(30{,}000\)\(0.0\)
P2 Least lifecycle costthe register weightslowCostB2 and C settlements: interim systems only\(30{,}000\)\(10.0\)
P3 Water-sensitive and circularcapital 9.8, operational 9.8, constructionEase 4.9, space 6.5, furtherTreatment 4.9, reuse 14, waterRequired 16, frontEnd 8.1, consumables 6.5, desludging 6.5, skill 8.1, telemetry 4.9waterSensitive, reuseno new ventilated pits; no urine diversion at metered premises; B2 and C settlements: interim systems only\(30{,}000\)\(0.0\)
P4 Operations firstcapital 9.1, operational 9.1, constructionEase 4.6, space 6.1, furtherTreatment 4.6, reuse 4.6, waterRequired 6.1, frontEnd 14, consumables 10, desludging 10, skill 14, telemetry 8minimalOMno new ventilated pits; no urine diversion at metered premises; B2 and C settlements: interim systems only\(30{,}000\)\(5.0\)

The three case-study zones under each policy, with the recommendation, its fit under that policy and its twenty-year cost:

ZoneP1P2P3P4
Z1 Dense B1 settlement beyond sewer reachUDDT
\(70.2\) · \(\mathrm{R}\,32{,}254\)
UDDT
\(70.2\) · \(\mathrm{R}\,32{,}254\)
UDDT
\(78.3\) · \(\mathrm{R}\,32{,}254\)
UDDT
\(67.4\) · \(\mathrm{R}\,32{,}254\)
Z2 Peri-urban B1 zone on yard taps, on-site serviceUDDT
\(73.3\) · \(\mathrm{R}\,32{,}254\)
VIP with FSM
\(69.5\) · \(\mathrm{R}\,23{,}426\)
UDDT
\(81.3\) · \(\mathrm{R}\,32{,}254\)
Pour-flush twin pits
\(64.8\) · \(\mathrm{R}\,28{,}239\)
Z3 B1 settlement within the catchment of a works with headroomComposting
\(69.9\) · \(\mathrm{R}\,40{,}432\)
VIP with FSM
\(67.3\) · \(\mathrm{R}\,23{,}426\)
Composting
\(80.4\) · \(\mathrm{R}\,40{,}432\)
Simplified sewer to works
\(72.0\) · \(\mathrm{R}\,39{,}749\)
On the live system · one site, three policies, three recommendations
Z3 on the Suitability tab under P1 (Composting), P2 least lifecycle cost (VIP with FSM) and P4 operations first (simplified sewer to the works): the policy is picked in the
Z3 on the Suitability tab under P1 (Composting), P2 least lifecycle cost (VIP with FSM) and P4 operations first (simplified sewer to the works): the policy is picked in the
Z3 on the Suitability tab under P1 (Composting), P2 least lifecycle cost (VIP with FSM) and P4 operations first (simplified sewer to the works): the policy is picked in the
Z3 on the Suitability tab under P1 (Composting), P2 least lifecycle cost (VIP with FSM) and P4 operations first (simplified sewer to the works): the policy is picked in the
Z3 on the Suitability tab under P1 (Composting), P2 least lifecycle cost (VIP with FSM) and P4 operations first (simplified sewer to the works): the policy is picked in the "How this was decided" pane and the site's run under it is shown; a policy the site has not been closed under is run on the pick. A recommendation is optimal relative to a policy.

Alignment \(A(\pi, \pi')\) over the three zones:

P1P2P3P4
P1\(1.0\)\(0.33\)\(1.0\)\(0.33\)
P2\(0.33\)\(1.0\)\(0.33\)\(0.33\)
P3\(1.0\)\(0.33\)\(1.0\)\(0.33\)
P4\(0.33\)\(0.33\)\(0.33\)\(1.0\)

Agreement counts recommendations; it does not say how far a wrong choice falls short. The graded measure follows Chandarman (2026), whose matching algorithms each embed an optimality principle and whose networks are scored under a policy's desirability index against that policy's own optimum. Here the algorithm is a decision rule applied across the zones, its network is the allocation it produces, and a policy's desirability of an allocation is the household-weighted mean fit under that policy of the systems chosen, a policy-excluded system counting zero. Alignment is that desirability relative to the policy's own closing:

\[ D_{\pi}(a) = \frac{\sum_{z} h_z\, S^{\pi}_{T_a(z)}}{\sum_{z} h_z}, \qquad \mathrm{Align}(a, \pi) = \frac{D_{\pi}(a)}{D_{\pi}(a_{\pi})}, \qquad \mathrm{Regret}(a,\pi) = 1 - \mathrm{Align}(a,\pi) \]

Seven decision rules are scored: closing under each of the four policies, and three practices a municipality might run without a method, the eThekwini default (sewer where available and metered, urine diversion where unsewered and unmetered, container-based where nothing on-site survives), least capital, and least lifecycle cost.

Decision ruleAlign to P1Align to P2Align to P3Align to P4Allocation Z1 · Z2 · Z3
P1\(1.0\)\(1.02\)\(1.0\)\(0.98\)UDDT · UDDT · Composting
P2\(0.5\)\(1.0\)\(0.49\)\(0.49\)UDDT · VIP with FSM · VIP with FSM
P3\(1.0\)\(1.02\)\(1.0\)\(0.98\)UDDT · UDDT · Composting
P4\(0.96\)\(0.98\)\(0.85\)\(1.0\)UDDT · Pour-flush twin pits · Simplified sewer to works
practice\(0.98\)\(1.0\)\(0.89\)\(1.01\)UDDT · UDDT · Simplified sewer to works
least capital\(0.95\)\(0.98\)\(0.88\)\(0.93\)Container-based · Container-based · Container-based
least lifecycle cost\(0.5\)\(1.0\)\(0.49\)\(0.49\)UDDT · VIP with FSM · VIP with FSM

Three readings. The municipality's current practice is already close to its own draft policy at \(0.98\) and coincides with the operations-first policy, so the method's first value to eThekwini is the reasons trail and the cost column rather than a different answer. The least-cost rule aligns at only \(0.5\) with the draft policy, because two of its three choices are systems the policy excludes, which is exactly the number a committee needs when someone proposes cost as the sole criterion. And least capital chooses the container-based system everywhere and still aligns at \(0.95\), which says the fit surface is flat among the survivors of the dense and peri-urban zones and that the decision there is being made by cost and conditions, not by fit.

The dense zone is policy-robust: every policy closes on the urine-diversion toilet, because the screen leaves three dry systems and no weighting separates them the other way. The other two zones are policy-sensitive. The least-cost policy, which carries no clause against new pits, recommends the ventilated pit in the peri-urban zone and, with no clause on metered premises, the urine-diversion toilet in the sewered-reach zone. The operations-first policy recommends the pour-flush twin pits in the peri-urban zone and the simplified sewer connection where the works has headroom, which is the answer the cost column already pointed to under the municipal policy. The municipal and the circular policies agree on every zone. Optimality aligns to a policy to the extent the alignment table shows, and the table is what a planner puts in front of a committee: which zones every policy agrees on, and on which zones the choice of policy is the decision.

Build

Creating the system

This page is the method as a reader follows it; the system is the same method as a municipality runs it. Everything above was written so that a second team could arrive at the same answer, and the test of that claim is a system that holds the catalogue, the criteria, the rules, the parameters and the policies as data, takes a settlement's measurements in, and returns the verdicts, the ranking, the cost and the closing with every reason attached. The reference implementation behind this page, a folder of scripts, is the oracle: the platform must return the same numbers on the same contexts, or a release does not ship.

The system is built on the platform the de-risking programme already uses. Its discipline is short: tables are the only truth, every change goes through a service verb that emits an event, every screen is a subscriber, and nothing is ever seeded. The system version therefore derives, section by section, from this page. Each row below names the section, what the system takes from it, and where that lands.

Section of this pageWhat the system takes from itWhere it lands
Step 1 · TypesThe sixteen systems as chains of catalogue components, the four classes, the three class testssystem (name, class, chain, the three answers) · component (Compendium and CEN codes, group, family) · the Units tab (templates by category) and the Register tab
Step 2 · ContextThe sixteen measurements, their bands and cut points, the evidence tier of each, the two derived criteria and the works they readcriterion (bands, unit, cut points, derivation, grade) · context (measurements as bands, tier per measurement, zone, works) · zone and works registers · the Sites tab with the survey form
Step 3 · ScreenThe rule register: a row per component, criterion and band with its verdict, condition, document and grade; the worst verdict along a chainrule (family rows expanded per component at import) · the engine verbs deriveContext and screen · the verdicts on the Suitability tab
Step 4 · RankFit as a weighted score under a policy; the twenty-year cost per household; the two never blendedparameter (per-system fit values, operating risk, weights, cost parameters, the reference cost) · policy (weights, goals, goal factor) · the verbs score and cost · the fit–cost plot
Step 5 · ResultThe closing algorithm, the conditions carried as obligations, the reasons trail, the exported assessmentassessment and assessmentRow · the verb close · the closing trail, exportAssessment and saveDocument on the Suitability tab
PoliciesA desirability calculation as a named policy; exclusion clauses as data; alignment of a decision rule to a policypolicy (envelope, margin, discount, clauses as {label, when}) · the verbs compare and alignRules
Sections A to EThe models and their first runs: the register, the numbers on the ranking, the cost model, the survey effort and evidence floor, the three validation checksThe engine's arithmetic, the evidence floor enforced at closing, the validation harness (build step 6)
Variables and ValuesEvery adjustable number with its status, grade, basis and the work that raises the gradeparameter as an editable register with history; the Centre engineer's surface
Case studiesThe three archetype zones under four policies, the back-test sites, the alignment matrixThe acceptance file the platform is tested against: the same contexts, the same numbers, three proofs run on every change
Literature and Behind the pathThe framework's position and the machinery behind each stepThe About area, the living documentation

16 tables under the san_ prefix, read straight from the service declaration. A reference-shaped column names the table it points to, so every form renders it as a selector and every list can join on it; an enumeration lists its values, so a form renders a select; a date-shaped column is typed as one, so it gets a picker. Codes and names that ride beside a reference (componentCode next to componentId, systemName next to systemId) exist for the label and the register's own language; the reference is the join.

Every reference is auto-wired by the platform as a parent-to-child scope and a child-to-parent selection, which is right for a row with one parent and wrong for a row with two: an assessment row belongs to its assessment, and selecting it must not select its system and rescope the list by system. The declaration therefore names the references that are joins only: assessmentRow.systemId, allocation.systemId, allocation.assessmentId, allocation.zoneId, allocation.worksId, assessment.policyId, context.worksId, context.zoneId, context.unitId, strategy.policyId, unit.companyId, unit.systemId, observation.unitId. Each row keeps one scoping parent, the surface's.

system · Systems

ColumnType · reference · valuesLabelGroup
idxstringIDkey
namestringNameessentialrequired
classenum {dry, nss, wess, sewered, sewdec}Classessentialrequired
chainjsonChain (component codes)essential
flushesbooleanQ1 flush?contextual
pipedToWorksbooleanQ2 piped to a works?contextual
waterRecoveredbooleanQ3 water recovered?contextual
sourcestringSourcesystem
createdAtdatetimeCreatedsystem

component · Components

ColumnType · reference · valuesLabelGroup
idxstringIDkey
codestringCodeessentialrequired
namestringNameessentialrequired
groupenum {UI, S, C, T, D}Groupessentialrequired
familystringFamily (rules address it)essential
sourcestringSourcesystem
createdAtdatetimeCreatedsystem

criterion · Criteria

ColumnType · reference · valuesLabelGroup
idxstringIDkey
keystringKeyessentialrequired
labelstringLabelessentialrequired
roleenum {gate, score, derived, both}Roleessentialrequired
unitstringUnitessential
bandsjsonBandscontextual
cutsstringCut pointscontextual
gradeenum {A, B, C, D}Gradecontextual
weightfloatWeightcontextual
goalstringGoal that doubles itcontextual
aggregationenum {mean, min, class}Chain aggregationcontextual
derivationjsonDerivation (lookup or source table)contextual
sourcestringSourcesystem
createdAtdatetimeCreatedsystem

rule · Rules

ColumnType · reference · valuesLabelGroup
idxstringIDkey
componentIdstring → componentComponentessentialrequired
componentCodestringComponent codeessentialrequired
criterionIdstring → criterionCriterionessentialrequired
criterionKeystringCriterion keyessentialrequired
bandstringBandessentialrequired
verdictenum {pass, cond, fail}Verdictessentialrequired
conditionstringCondition (obligation)contextual
sourceKindenum {register, fieldRecord}Source kindcontextualrequired
sourceRefstringSource document / clause / HAZOP idcontextual
gradeenum {A, B, C, D}Gradecontextual
createdAtdatetimeCreatedsystem

parameter · Parameters

ColumnType · reference · valuesLabelGroup
idxstringIDkey
sectionstringSectionessentialrequired
keystringParameteressentialrequired
valuejsonValueessential
unitstringUnitessential
statusenum {sourced, assumed, missing}Statusessentialrequired
gradeenum {A, B, C, D}Gradeessential
basistextBasiscontextual
rangejsonRangecontextual
sourcestringSource documentcontextual
createdAtdatetimeCreatedsystem
updatedAtdatetimeUpdatedsystem

policy · Policies

ColumnType · reference · valuesLabelGroup
idxstringIDkey
codestringCodeessentialrequired
namestringNameessentialrequired
basistextBasiscontextual
weightsjsonWeightsessential
goalFactorfloatGoal factoressential
goalsjsonGoals forcedessential
exclusionsjsonExclusion clausesessential
envelopefloatCapital envelope per household (R)essential
marginfloatFit margin at closingessential
discountfloatDiscount ratecontextual
statusenum {sourced, assumed, missing}Statuscontextual
createdAtdatetimeCreatedsystem

company · Companies

ColumnType · reference · valuesLabelGroup
idxstringIDkey
namestringCompanyessentialrequired
kindenum {manufacturer, provider, municipality, research}Kindessentialrequired
contactstringContactcontextual
sourcestringSourcesystem
createdAtdatetimeCreatedsystem

unit · Units

ColumnType · reference · valuesLabelGroup
idxstringIDkey
companyIdstring → companyCompanyessentialrequired no cascade
namestringUnitessentialrequired
classenum {dry, nss, wess, sewered, sewdec}Categoryessentialrequired
systemIdstring → systemCatalogued templateessentialno cascade
capacityHouseholdsintegerHouseholds per unitcontextual
capitalPerHhfloatCapital per household (R)contextual
opexPerHhfloatOperating cost per household per year (R)contextual
statusenum {monitored, available, withdrawn}Statuscontextual
sourcestringSourcesystem
createdAtdatetimeCreatedsystem

zone · Zones

ColumnType · reference · valuesLabelGroup
idxstringIDkey
namestringSettlementessentialrequired
municipalitystringMunicipalitycontextual
planningUnitstringPlanning unitcontextual
wardstringWardcontextual
householdsintegerHouseholdsessential
upgradingCategorystringUpgrading categoryessential
latfloatLatitudecontextual
lngfloatLongitudecontextual
geometrySourcestringGeometry sourcecontextual
sourcestringSourcesystem
createdAtdatetimeCreatedsystem

works · Treatment works

ColumnType · reference · valuesLabelGroup
idxstringIDkey
namestringWorksessentialrequired
technologystringTechnologycontextual
classOfWorksstringClass of workscontextual
designCapacityKldfloatDesign capacity (kL/d)essential
operationalCapacityPctfloatOperational capacity (%)essential
microCompliancePctfloatMicrobiological compliance (%)contextual
physicalCompliancePctfloatPhysical compliance (%)contextual
chemicalCompliancePctfloatChemical compliance (%)contextual
technicalSkillsPctfloatTechnical skills (%)contextual
crr2023PctfloatCumulative risk 2023 (%)contextual
riskClassstringRisk classessential
sourcestringSourcesystem
createdAtdatetimeCreatedsystem

context · Contexts

ColumnType · reference · valuesLabelGroup
idxstringIDkey
zoneIdstring → zoneZoneessentialno cascade
worksIdstring → worksReceiving workscontextual
labelstringLabelessentialrequired
measurementsjsonMeasurements (key → band)essential
tiersjsonTier per measurementcontextual
goalsjsonZone goalscontextual
meteredbooleanMetered premisescontextual
installedSystemstringInstalled system (monitored site)contextual
unitIdstring → unitInstalled unitcontextualno cascade
hazardCategoriesjsonHazard-register categories recordedcontextual
surveyedAtdatetimeSurveyedsystem
createdAtdatetimeCreatedsystem

assessment · Assessments

ColumnType · reference · valuesLabelGroup
idxstringIDkey
contextIdstring → contextContextessentialrequired no cascade
policyIdstring → policyPolicyessentialrequired
policyCodestringPolicy codeessential
labelstringLabelessential
recommendationstringRecommendationessential
closingTrailjsonClosing trailcontextual
assumedParamsjsonAssumed parameters acceptedcontextual
runAtdatetimeRunsystem
createdAtdatetimeCreatedsystem

assessmentRow · Assessment rows

ColumnType · reference · valuesLabelGroup
idxstringIDkey
assessmentIdstring → assessmentAssessmentessentialrequired
systemIdstring → systemSystemessentialrequired
systemNamestringSystem nameessentialrequired
verdictenum {pass, cond, fail}Verdictessentialrequired
decidingRulesjsonDeciding rulescontextual
conditionsjsonConditionscontextual
fitfloatFitessential
fitPartsjsonFit decompositioncontextual
costfloatTwenty-year cost per householdessential
costPartsjsonCost partscontextual
excludedBystringExcluded bycontextual
createdAtdatetimeCreatedsystem

observation · Observations

ColumnType · reference · valuesLabelGroup
idxstringIDkey
classenum {dry, nss, wess, sewered, sewdec}Classessentialrequired
metricenum {uptime, timeWithinSpec}Metricessentialrequired
valuefloatValue (%)essentialrequired
unitstringUnitcontextual
sitesintegerSites observedcontextual
unitIdstring → unitUnit observedcontextualno cascade
periodFromdatePeriod fromessential
periodTodatePeriod toessential
sourcestringSourceessential
createdAtdatetimeCreatedsystem

strategy · Strategies

ColumnType · reference · valuesLabelGroup
idxstringIDkey
codestringCodeessentialrequired
namestringNameessentialrequired
policyIdstring → policyPolicyessentialrequired
policyCodestringPolicy codeessential
startYearintegerStart yearessential
targetYearintegerTarget yearessential
envelopefloatCapital envelope, total (R)essential
statusenum {draft, adopted, closed}Statuscontextual
notestextNotescontextual
createdAtdatetimeCreatedsystem

allocation · Allocations

ColumnType · reference · valuesLabelGroup
idxstringIDkey
strategyIdstring → strategyStrategyessentialrequired
strategyCodestringStrategy codeessential
zoneIdstring → zoneZoneessentialrequired
assessmentIdstring → assessmentAssessmentcontextual
systemIdstring → systemSystemessentialrequired
systemNamestringSystem nameessentialrequired
zoneNamestringZone nameessential
classenum {dry, nss, wess, sewered, sewdec}Classessential
worksIdstring → worksReceiving workscontextual
yearintegerYearessential
capitalfloatCapital (R)essential
householdsintegerHouseholdsessential
createdAtdatetimeCreatedsystem

A labeller is a declaration on the table, and every selector, card, picker and search modal inherits it at once. The canon: the title line carries what a person recognises, the subtitle carries the discriminator, and an identifier never stands as a title. Where a table's human name lives in a referenced row, the name rides beside the reference for this purpose.

TableTitleSubtitlePillThe reading
system{name}{class}classthe name a planner knows; the class beside it, since the class is what the strategy allocates
component{name}{group} · {code}groupthe technology by its name; the group and Compendium code beneath, the way an engineer cites it
criterion{label}{role} · {unit}rolethe measurement by its label; its role (gate, derived, score) and unit beneath
rule{componentCode} on {criterionKey} = {band}{verdict} · {sourceRef}verdicta rule reads as a sentence, component on criterion equals band; the verdict and the document beneath
parameter{section} · {key}{status} · grade {grade}gradesection and key, since a parameter is only meaningful inside its model; status and grade beneath
policy{name}{code} · margin {margin} · envelope R{envelope}statusthe policy by its name; the code and the two numbers that change a closing, margin and envelope, beneath
company{name}{kind}kindthe company by its name; its kind beneath (manufacturer, provider, municipality)
unit{name}{class} · {status}classthe unit by its name; its category and status beneath, the way a planner shortlists it
zone{name}{planningUnit} · ward {ward} · {upgradingCategory}upgradingCategorythe settlement by its name; planning unit, ward and upgrading category beneath, the way the IDP lists it
works{name}{technology} · {operationalCapacityPct}% of design · {riskClass}riskClassthe works by its name; technology, load against design and risk class beneath, the way Green Drop reports it
context{label}surveyed {surveyedAt}–the survey by its label; the survey date beneath, never an identifier
assessment{label}{recommendation} · run {runAt}–context and policy code as the label; the recommendation and the run time beneath
assessmentRow{systemName}{verdict} · fit {fit} · cost R{cost}verdictthe system by its name; verdict, fit and cost beneath, the three things read at a glance
observation{class} · {metric}{value} {unit} · {periodFrom} to {periodTo} · {source}classclass and metric as the label; value, period and source beneath
strategy{name}{code} · target {targetYear} · envelope R{envelope}statusthe strategy by its name; code, target year and envelope beneath
allocation{systemName}{zoneName} · year {year} · {households} householdsclassthe system allocated; the strategy, year and households beneath

Every area is one of the platform's named layouts, populated with shared bindings and read against the same tests. The frame is the instrument, not a web page: one navigation row, the control column on the left at one quarter of the width (the platform's control-stage grid is 1 : 3, so 340 to 380 px on a laptop screen of 1366 to 1536 px), the stage at three quarters, a 24 px status line at the foot. Inside the frame the surface is continuous, divided by hairlines; cards represent objects only, never regions. The control column is one exclusive accordion ordered by dwell time: the section where the work happens opens first, a selector folds once the choice is made and stays one click away. The stage is one persistent surface that reads top to bottom: the numbers of the moment as plain chips, then the one graphical element a domain expert recognises at a glance, filling the width, then the facets of the selected record side by side in a two-column grid so they are read together, then the trail. The first render is a working render: the first or latest record is selected, and a genuinely empty table shows a named empty state, never an instruction to click. A pick drives the stage (owner ruling 5 September 2026): selecting a row in any list changes the central element and every facet on the stage to that record within the event, and nothing stays showing the previous record; a selector that folds names its choice in its own header; where a pick has nothing to show, the stage says so by name (not assessed, not placed) rather than keeping the old picture. Switching a section hides and shows; nothing is rebuilt. Primary text stays near-black at about 13 px; density comes from tight rows, not smaller type.

Sites — what is this site like built 4 Sep

SanPath · Sites — what is this site like status line · counts · selection · sync control · ¼ (360 px at 1440) stage · ¾ Sitesopen Surveyfolded 1Chips 2Where it is 3The site's variables 4Surveys of this site

Layout. control-stage; the rail lists sites, the survey form folded beneath. Central element. the map, full width, centred on the picked site; beneath it the site's variables as aligned rows, every band strip the same width, the recorded band highlighted, the evidence tier beside it.

Control column (¼), top to bottomHoldsState
Sitesthe settlement register, searchable, with the latest verdict as a pill (`zone.bindSelector`; `zone.bindSelectEditor` when the engineer edits, typing lat, lng and source)open
Surveythe survey form for the picked site (label, receiving works, metering, goals; `uiForm` → `saveContext`); the bands are set on the variables panefolded
#Stage (¾), read top to bottomHoldsHeight
1Chipssite · households · category · receiving works · variables recorded · below the evidence floor · surveyed · latest verdict · allocated · point8%
2Where it is`zone.bindMap` across the full width, centred on the picked site: click to place an unplaced site, drag to correct, both through `setZoneGeometry`38%
3The site's variablesaligned rows: a fixed label column, the bands as a segmented strip of one width for every row with the recorded band filled (the survey's input), a fixed tier column; one muted caption of unit and cut points under each strip; derived variables greyed and marked derived40%
4Surveys of this site`context.bindSelector` of the site's surveys, latest first; a pick loads that survey into the variables and the form14%

First render. the site of the latest assessment is selected (else the latest surveyed site, else the first). On a pick. a site → the chips, its variables with their recorded values and tiers, the map centred on its point, its surveys; a survey in the history → the variables and the form; a site with no survey → that state named, the rows unfilled for recording. Empty. a site without a survey: the callout names it and every row renders unfilled for recording.

Sites with a site picked: the register in the control column; on the stage the map centred on the site, its variables as aligned rows, its surveys
Sites with a site picked: the register in the control column; on the stage the map centred on the site, its variables as aligned rows, its surveys
Central element: the site's point on the eThekwini basemap, full width; a click places an unplaced site, a drag corrects a marker
Central element: the site's point on the eThekwini basemap, full width; a click places an unplaced site, a drag corrects a marker
The site's variables: a fixed label column, every band strip the same width with the recorded band highlighted, the evidence tier in a fixed column, unit and cut points captioned under each strip; derived variables greyed
The site's variables: a fixed label column, every band strip the same width with the recorded band highlighted, the evidence tier in a fixed column, unit and cut points captioned under each strip; derived variables greyed
Surveys of this site: the history, latest first; a pick loads that survey into the variables and the form
Surveys of this site: the history, latest first; a pick loads that survey into the variables and the form
Control column: the site register with search, add and the latest verdict as a pill; the survey form folded beneath
Control column: the site register with search, add and the latest verdict as a pill; the survey form folded beneath

Units — what units and categories exist, with what numbers built 4 Sep

SanPath · Units — what units and categories exist, with what numbers status line · counts · selection · sync control · ¼ (360 px at 1440) stage · ¾ Categoriesopen 1Chips 2Cost across the categories 3Units in this category 4Catalogued templates 5The picked unit or template

Layout. control-stage; the rail lists the five categories. Central element. the ranges across categories: one box per category of product, the catalogued templates as its members, the metric chosen above (twenty-year cost, capital, operating, desludging).

Control column (¼), top to bottomHoldsState
Categoriesthe five categories of product with their counts of templates and units (a `uiCollection` list: the category is the schema's enum, not a row)open
#Stage (¾), read top to bottomHoldsHeight
1Chipscategory · templates · units · companies · monitored sites · twenty-year cost range · capital range · observed uptime8%
2Cost across the categories`system.bindBoxPlot` (valueField = the chosen metric, groupField = category); the metric as a segmented control above it40%
3Units in this category | Catalogued templatesleft: `unit.bindSelector` — unit, company, template, monitored sites, capital where stated; right: `system.bindSelector` — components, twenty-year cost, capital32%
4The picked unit or templatethe unit: company, category, template, status, households per unit, capital and operating per household (or "not stated"), the category's observed uptime, its monitored sites with their hazard categories; the template: cost parts, basis, the chain as a stepper, fit values, the units built on it20%

First render. all five categories (the chips count the whole register), no member picked. On a pick. a category → the chips repaint to it, the units and templates filter to it, the plot keeps every category for comparison; a unit → its company, template, numbers, monitored sites and record; a template → its chain, cost parts, fit values and the units built on it. Empty. a category with no unit: the units pane names it; a number a source does not state reads "not stated", never a guess.

Units with the recirculating category picked and a unit picked: the categories in the control column; the ranges, the members and the picked unit on the stage
Units with the recirculating category picked and a unit picked: the categories in the control column; the ranges, the members and the picked unit on the stage
Central element: one box per category of product, the templates as members, the metric chosen above
Central element: one box per category of product, the templates as members, the metric chosen above
Units in this category: each with its company, its template and its monitored sites
Units in this category: each with its company, its template and its monitored sites
Catalogued templates of the category: components, twenty-year cost and capital per household
Catalogued templates of the category: components, twenty-year cost and capital per household
The picked unit: company, template, status, the numbers a source states, the category's observed uptime, its monitored sites and their hazard categories
The picked unit: company, template, status, the numbers a source states, the category's observed uptime, its monitored sites and their hazard categories
Control column: the five categories with their counts of templates and units
Control column: the five categories with their counts of templates and units

Suitability — which options fit this site, at what cost, with what risks built 4 Sep

SanPath · Suitability — which options fit this site, at what cost, with what risks status line · counts · selection · sync control · ¼ (360 px at 1440) stage · ¾ Sitesopen 1Chips 2The options for this site 3The evidence for the picked option 4Fit beside cost 5How this was decided

Layout. control-stage; the rail lists sites. Central element. the options as cards, the recommendation first then by fit: each with its verdict (suitable · with conditions · ruled out · excluded by policy), fit, twenty-year cost and capital per household, and the risks and concerns in words.

Control column (¼), top to bottomHoldsState
Sitesthe settlement register with the verdict as a pill (`zone.bindSelector`; the same selection as the Sites tab)open
#Stage (¾), read top to bottomHoldsHeight
1Chipssite · recommendation · suitable options · ruled out · excluded by policy · cost of the recommendation · policy · assessed8%
2The options for this site`assessmentRow.bindSelector` as cards, scoped to the run by `assessment.bindChildTable`; risks = the rules that condition or rule the option out, in words; concerns = policy exclusion, assumed cost parameters, conditions to accept44%
3The evidence for the picked option | Fit beside costleft: the rules behind the verdict as callouts, each in words with its code, document and grade, then the fit decomposition; right: `assessmentRow.bindPlot`, fit up, cost across, by verdict30%
4How this was decidedpolicy and time of the run, the closing trail step by step; the doors: the policy list to assess under another policy, the evidence-floor switch, Run assessment, Export assessment, Allocate to the latest strategy18%

First render. the site of the latest assessment is selected and its run shown, the recommendation card selected. On a pick. a site → its latest run under the policy in force (else it is assessed now, else the refusal is named); a policy in the door → the run under it; an option card → the evidence for it; the pick is shared with Sites. Empty. no survey: named, with the door to Sites; surveyed but never assessed: assessed on the pick under the policy in force; refused by the evidence floor: the refusal named with the switch in view.

Suitability with a site picked: the verdict chips, the options as cards, the evidence and the plot, how it was decided with the doors
Suitability with a site picked: the verdict chips, the options as cards, the evidence and the plot, how it was decided with the doors
Central element: the options as cards, the recommendation first — verdict, fit, twenty-year cost and capital, the risks and concerns in words
Central element: the options as cards, the recommendation first — verdict, fit, twenty-year cost and capital, the risks and concerns in words
The evidence for the picked option: each rule in words with its code, document and grade, then the fit decomposition
The evidence for the picked option: each rule in words with its code, document and grade, then the fit decomposition
Fit beside cost: the survivors as points, coloured by verdict
Fit beside cost: the survivors as points, coloured by verdict
How this was decided: the policy, the closing trail, and the doors — another policy, the evidence-floor switch, run, export, allocate
How this was decided: the policy, the closing trail, and the doors — another policy, the evidence-floor switch, run, export, allocate
Control column: the sites with their verdict as a pill; the same pick as the Sites tab
Control column: the sites with their verdict as a pill; the same pick as the Sites tab

Strategy — how the verdicts add up across sites built (unchanged)

SanPath · Strategy — how the verdicts add up across sites status line · counts · selection · sync control · ¼ (360 px at 1440) stage · ¾ Strategiesopen Allocatefolded 1Chips 2Capital by year 3Allocations 4Shared resources 5Strategy document

Layout. control-stage. Central element. capital by year against the envelope: bars of allocated capital per year, one colour per class.

Control column (¼), top to bottomHoldsState
Strategiesnamed strategies with target year and envelope (`strategy.bindSelectEditor`)open
Allocatethe closed assessments under the strategy's policy whose zone is not yet allocated (`assessment.bindSelector`); the year; Allocate the recommendationfolded
#Stage (¾), read top to bottomHoldsHeight
1Chipsstrategy · policy · zones allocated · households served · capital committed of envelope · horizon6%
2Capital by year`allocation.bindPlot` bar by year grouped by class40%
3Allocations | Shared resourcesleft: `allocation.bindSelector` by zone with class pill, year, households, capital; right: works headroom against draw, the desludging fleet against events, then the picked allocation or candidate36%
4Strategy documentExport strategy → the phased plan as a document18%

First render. the latest strategy that holds allocations is selected. On a pick. a strategy → chips, capital by year, allocations, balances; a candidate → what allocating it would commit; an allocation → its detail beside the balances (fit, cost, conditions, the run it rests on). Empty. no strategy yet: the named empty state with New strategy.

Strategy with the demo plan picked: chips for policy, zones, households, capital and horizon; capital by year; allocations and shared resources
Strategy with the demo plan picked: chips for policy, zones, households, capital and horizon; capital by year; allocations and shared resources
Central element: capital by year, one bar per year, by class
Central element: capital by year, one bar per year, by class
Allocations: zone, system, year, households and capital; a pick shows its detail beside the balances
Allocations: zone, system, year, households and capital; a pick shows its detail beside the balances
Shared resources: works headroom and the desludging fleet against the allocations, and the picked allocation's detail
Shared resources: works headroom and the desludging fleet against the allocations, and the picked allocation's detail
Strategy document: the export door for the plan as a circulating document
Strategy document: the export door for the plan as a circulating document
Control column: the strategies list and the allocate section
Control column: the strategies list and the allocate section

Register — is the engine right (engineer) built 4 Sep

SanPath · Register — is the engine right (engineer) status line · counts · selection · sync control · ¼ (360 px at 1440) stage · ¾ Monitored sitesopen Observed performancefolded Componentsfolded Parametersfolded Policiesfolded Units and companiesfolded 1Chips 2Discrepancy report 3Back-test 4The picked monitored site 5The picked component 6The picked parameter or policy

Layout. control-stage; one register per rail section, one pane per kind on the stage. Central element. the discrepancy report: class by criterion, the register's operating-risk score against the band the observed record puts the class in, flagged where they differ by the trigger.

Control column (¼), top to bottomHoldsState
Monitored sitescontexts carrying an installed unit and a hazard register (`context.bindSelector`), each with survives or fails and its overlapopen
Observed performance`observation.bindSelectEditor` (recorded through `recordObservation`)folded
Components`component.bindSelector`folded
Parameters`parameter.bindSelectEditor`folded
Policies`policy.bindSelectEditor`folded
Units and companies`unit.bindSelectEditor`folded
#Stage (¾), read top to bottomHoldsHeight
1Chipsmonitored sites · installed system survives · mean overlap J · observations · criteria flagged · rules · parameters · units8%
2Discrepancy reporta row per class: the observed value and its band, then each operating-risk criterion's register score beside the band, flagged ⚑ at or beyond the trigger32%
3Back-test | The picked monitored siteleft: every monitored site with the installed system, survives or fails, raised against recorded, J; right: the picked site's raised conditions with their categories and the watch conditions of its class30%
4The picked component | The picked parameter or policyleft: the component's group, family, source, the templates using it, and `rule.bindSelector` of every rule it reads; right: the parameter's value, status, grade, basis, range and source, or the policy's weights and exclusion clauses30%

First render. the report and the back-test run on render from what the tables hold; nothing picked in the register sections. On a pick. a monitored site → its raised conditions against the recorded categories; an observation → its class brought to the front of the report; a component → every rule it reads and the templates that use it; a parameter or a policy → its own pane. Empty. no monitored site or no observation: the chips say so and the report rows read "no observation"; an unpicked register pane says what to pick.

Register (engineer) with a monitored site, an observation and a component picked: the registers in the control column; the report, the back-test and the picked records on the stage
Register (engineer) with a monitored site, an observation and a component picked: the registers in the control column; the report, the back-test and the picked records on the stage
Central element: the register's operating-risk score against the band the observed record puts each class in, flagged where they differ
Central element: the register's operating-risk score against the band the observed record puts each class in, flagged where they differ
Back-test: does each installed system survive its own site, and what was raised against what was recorded
Back-test: does each installed system survive its own site, and what was raised against what was recorded
The picked monitored site: raised conditions beside the categories its hazard register recorded
The picked monitored site: raised conditions beside the categories its hazard register recorded
The picked component: its group, family, source, the templates using it, and every rule it reads
The picked component: its group, family, source, the templates using it, and every rule it reads
Control column: monitored sites, observed performance, components, parameters, policies, units and companies, one kind per section
Control column: monitored sites, observed performance, components, parameters, policies, units and companies, one kind per section

About built; the artefact door 5 Sep

SanPath · About status line · counts · selection · sync control · ¼ (360 px at 1440) stage · ¾ –open 1What SanPath is for 2The method as a document 3Demo world (engineer) 4Who uses it, and for what

Layout. reader. Central element. the document: this page's narrative, the meta plan and the build state.

Control column (¼), top to bottomHoldsState
–no control column: About is a readeropen
#Stage (¾), read top to bottomHoldsHeight
1What SanPath is forthe intention and the sources, narrated25%
2The method as a documentthis artefact: Open the artefact (a new tab) or Read it here (the page mounted inside the tab, style-isolated, its own tabs and equations working)25%
3Demo world (engineer)the door that builds the demo world through the verbs on a demo backend15%
4Who uses it, and for whatthe three user types and the five tabs as their questions35%

First render. the narrative. On a pick. a section → the document scrolls to it. Empty. –.

The About tab: the intention, the artefact door, the demo-world door for the engineer, and the users
The About tab: the intention, the artefact door, the demo-world door for the engineer, and the users
The method as a document: Open the artefact in a new tab, or Read it here, which mounts this page inside the tab with its tabs and equations working
The method as a document: Open the artefact in a new tab, or Read it here, which mounts this page inside the tab with its tabs and equations working

The tests every area is read against. Crop the screenshot to the stage: the purpose is obvious in one second or the hierarchy is wrong. Flatten it to grey: navigation, controls and data are still told apart by shape. On first load the largest element is data, not an instruction. After selecting a record, its facets are visible together with no further click, and picking any other row in any list changes the central element and every facet to that row (the proof `Tests/sanpath-selection.mjs` drives one pick per list on every surface). No region is a card; no form sits on the stage; no control column exceeds a quarter at laptop width; no text below 13 px carries meaning.

A system composes services; a service owns tables, verbs and the views over them, and is influenced only through configuration. This tab maps each service the SanPath system composes to what it does for the method, the configuration it takes, and its state; then the SanPath service's own contract: every configuration knob with its default and meaning, every functional element (importers, engine verbs, export, views) with its settings, what it reads and writes, what it emits and the door that exposes it, and every event with the subscribers that consume it. The register is read from the service declaration, not retyped.

The services the system composes

ServiceClass · prefixWhat it does for SanPathConfigurationState
SanPathSanPathService · san_the method as data and verbs: catalogue, register, parameters, policies, companies and units, zones, works, contexts, assessments; the engine; the five surfacesconfig.services.sanpath = { api: "mserp", prefix: "san_", options: {…} } — the options are the contract in the next table; the api is the municipality's own MSERP endpoint, the prefix is fixedbuilt
MemberMemberService (Service.Core.js) · mbr_identity and roles: the planner, the engineer and the reader are members with roles under the system's parent group; tab gating and the engineer's edit rights read them; sessions and API keys for a municipality's integrationconfig.services.member = { api: "mserp", prefix: "mbr_" } · config.rbac = { parentGroupCode: "sanpath", adminRoles: ["engineer", "platform-admin"] } · tabs carry roles: Sites and Suitability → planner, engineer; Units and Strategy → everyone; Register → engineer; About → everyone · applyLoginShield: true on a hosted deployment (false only on the auth-off sandbox)wired; roles gate on post-login
AuditAuditService · aud_the record of every domain event: the system bus is tapped, so each san: event (a run closed, a register imported, an export) lands as an aud_event row with the actor, and the engineer's register edits carry their trailconfig.services.audit = { api: "mserp", prefix: "aud_" }; the tap is the default (tapBus true); nothing else to setwired by the frame
FilesFilesService · fil_the exported assessment and the strategy document as files a municipality can circulate: Save to Files on Suitability and on Strategy calls saveDocument, which uploads the Markdown through Files.uploadFile into one 'SanPath exports' folder (created once); the server holds the bytesconfig.services.files = { api: "mserp", prefix: "fil_" }; the instance's /upload route must accept a signed-in session (it does on both hosted instances)wired; Save to Files live 5 Sep
TagTagService · tag_not used by any SanPath feature; the frame instantiates it by default. Reviewed and dropped from the loadout until a feature names it (a tag on a zone would be accretion)removed from config.servicesdropped

SanPath service · configuration contract

OptionDefaultMeaning
defaultPolicy"P1"the policy a verb runs under when none is named (the municipality's own policy)
evidenceFloortrueenforce the evidence floor at closing: a gate measurement below the floor (parameter survey.evidenceFloor) refuses close unless the planner accepts it
acceptConditionstruethe closing default for conditions: accepted with the municipality named as responsible party (false drops every conditional survivor)
persistAssessmentstrueclose writes assessment and assessmentRow rows (false returns the result only)
discountRatenulloverrides the policy discount rate when set; null = the policy's rate, else the first illustrative rate of costGlobal.discountRates
routeKmnulloverrides the route length when set; null = the context's measurement routeKm, else costGlobal.routeKm
editablefalsethe engineer's edit rights on the catalogue and the registers (chain editing, parameters, policies); the system sets it from the member's roles on post-login, true on the auth-off sandbox
tiers["record", "visit", "field test", "engagement", "assumed"]the evidence tiers the survey form offers per measurement (parameter survey.evidenceFloor names which may close)
goals["lowCost", "minimalOM", "waterSensitive", "reuse", "localJobs"]the goals a planner may declare for a zone; each doubles the criteria it touches
mapCenter[31.02, -29.86]the Sites map's starting centre [lng, lat] when no site carries geometry (eThekwini); a deployment sets its municipality
mapZoom9the Sites map's starting zoom

SanPath service · functional elements

ElementKindSettingsReadsWritesEmitsDoor
importRulesimporter{ registry: rules.json }the register (catalogue, criteria, rules, lookup)component · criterion · rule (new rows inserted; held rows whose verdict, condition, source or grade changed are updated)san:rulesImportedTests/sanpath-import.mjs; the engineer's registers (step 4)
importSystemsimporter{ registry: systems.json }the sixteen chainssystemsan:systemsImportedas above
importParametersimporter{ registry: parameters.json }the parameter registerparameter (new rows inserted; held rows whose value, range, unit, status, grade, basis or source changed are updated) · criterion (score rows)san:parametersImportedas above
importPoliciesimporter{ registry: policies.json }the policy registerpolicysan:policiesImportedas above
importZonesimporter{ registry: zones.<municipality>.json }the settlement registerzonesan:zonesImportedas above
importUnitsimporter{ registry: units.json }the companies and their units (the de-risking field record; a supplier register later)company · unitsan:unitsImportedas above; the Units tab reads them
importWorksimporter{ registry: works.<municipality>.json }the works registerworkssan:worksImportedas above
deriveContextengine{ contextId }context · criterion.derivation · workscontext.measurements (gwRisk, worksHeadroom)san:contextDerivedSites on save; Suitability reads bands through screen
screenengine{ contextId }context · system · component · rule–san:screenedSuitability (inside close)
scoreengine{ contextId, policyCode?, survivors? }policy · parameter (systemFit, operatingRisk, costReference, cost:*) · criterion (score rows)–san:scoredSuitability (inside close)
costengine{ systemName, policyCode? | rho?, routeKm? }parameter (cost:*, costGlobal)–san:costedSuitability (inside close); Units (template cost)
closeengine{ contextId, policyCode?, accepted?, acceptBelowFloor?, persist? }all of the above · survey.evidenceFloorassessment · assessmentRowsan:assessmentClosedSuitability · on the site pick, and Run assessment
compareengine{ contextId, policyCodes?, accepted?, acceptBelowFloor? }as close–san:policiesComparedTests/sanpath-engine.mjs (the policy comparison)
alignRulesengine{ contextIds, policyCodes?, accepted?, acceptBelowFloor? }as close · zone.households–san:rulesAlignedStrategy area (step 5); Tests/sanpath-engine.mjs
saveContextsurvey{ contextId?, zoneId, label, measurements, tiers, metered, goals, worksId }criterion (bands, tiers)context (create or update), then deriveContextsan:contextSaved · san:contextDerivedSites · Save survey
deleteContextsurvey{ contextId }assessment (refuses when runs exist)context (delete)san:contextDeletedSites · Delete survey
setZoneGeometryzone{ zoneId, lat, lng, source } (lat and lng null to clear)zonezone.lat · zone.lng · zone.geometrySourcesan:zoneGeometrySetSites · click the map to place the picked site; drag a marker; the API (updateEntry on san_zone)
importZoneGeometryimporter{ rows: [{ name | zoneId, lat, lng }], source }zone (matched by name or id)zone.lat · zone.lng · zone.geometrySource per matched rowsan:zoneGeometryImportedthe engineer's import (a CSV from a GIS layer or a gazetteer); unmatched names are listed, never guessed
createStrategystrategy{ code, name, policyCode?, startYear?, targetYear?, envelope?, notes? }policystrategysan:strategyCreatedStrategy · New strategy
allocatestrategy{ strategyId, assessmentId, year? }strategy · assessment · assessmentRow (the recommendation) · context · zoneallocationsan:allocatedStrategy · Allocate; Suitability · Allocate to the latest strategy
deallocatestrategy{ allocationId }allocationallocation (delete)san:deallocatedStrategy · the allocation list
strategyBalancestrategy{ strategyId }strategy · allocation · works · parameter (strategy, cost:*)–san:strategyBalancedStrategy · the balances and the capital-by-year plot
strategyDocumentexport{ strategyId }strategy · allocation · the balance–san:strategyExportedStrategy · Export strategy
backtestvalidation{ contextIds? } (default: every context with an installed system)context (installedSystem, hazardCategories) · the screen · parameter (validation.conditionCategories, watchThreshold; fit.operatingRisk)–san:backtestedRegister · the back-test table
discrepancyReportvalidation{ }observation · parameter (validation.discrepancyBands, recalibrationTrigger; fit.operatingRisk)–san:discrepancyReportedRegister · the discrepancy report; the engineer edits the register by hand
recordObservationvalidation{ class, metric, value, sites?, periodFrom, periodTo, source }–observationsan:observationRecordedRegister · Record observation; the InfraTrack import (later)
saveDocumentexport{ kind: assessment | strategy, id }the export verbs; files.folderfiles.folder (once) · files.file through Files.uploadFilesan:documentSavedSuitability · Save to Files; Strategy · Save to Files
exportAssessmentexport{ assessmentId }assessment · assessmentRow · context · policy–san:assessmentExportedSuitability · Export assessment
renderSitesview(stage)zone · context · criterion · works · assessment · allocationthrough saveContext / deleteContext / setZoneGeometry–the Sites tab
renderUnitsview(stage)system · unit · company · context · observation · component · rule · parameter––the Units tab
renderSuitabilityview(stage)zone · context · assessment · assessmentRow · policy · strategythrough close / exportAssessment / allocate–the Suitability tab
renderStrategyview(stage)strategy · allocation · assessment · zone · worksthrough the strategy verbs–the Strategy tab
renderRegisterview(stage)context (monitored sites) · observation · component · rule · parameter · policy · unit · companythrough recordObservation and the schema editors when editable–the Register tab (engineer)

SanPath service · events and their subscribers

EventPayloadSubscribers
san:systemsImported{ count, inserted, source, version }the import harness (counts); the Audit tap
san:rulesImported{ count, inserted, updated, components, criteria, source, version }the import harness (counts); the Audit tap
san:parametersImported{ count, inserted, updated, source, version }the import harness (counts); the Audit tap
san:policiesImported{ count, inserted, source, version }the import harness (counts); the Audit tap
san:zonesImported{ count, inserted, source, version }the import harness (counts); the Audit tap
san:worksImported{ count, inserted, source, version }the import harness (counts); the Audit tap
san:unitsImported{ count, inserted, companies, sites, source, version }the import harness (counts); the Audit tap
san:contextDerived{ contextId, bands }the Contexts surface (derived rows repaint, step 4); the Audit tap
san:screened{ contextId, survivors, eliminated }the Contexts gates preview (step 4); the Audit tap
san:scored{ contextId, policyCode, ranked }the Audit tap
san:costed{ systemName, rho, total, status }the Catalogue cost card (step 4); the Audit tap
san:assessmentClosed{ assessmentId, contextId, policyCode, recommendation }the Suitability surface (selects the new run and its recommendation); the Sites chips (latest verdict); the Audit tap; the Strategy area (an allocation offered for the zone)
san:policiesCompared{ contextId, policyCodes, agreement }the Decision run note; the Audit tap
san:rulesAligned{ contextIds, algorithms, policies, alignment }the Strategy area (step 5); the Audit tap
san:assessmentExported{ assessmentId, markdown }the Decision export pane; the Files save (step 4); the Audit tap
san:documentSaved{ fileId, name, folderId, kind, id }the import harness (counts); the Audit tap
san:contextSaved{ contextId, zoneId, created }the import harness (counts); the Audit tap
san:backtested{ sites, survives, meanOverlap }the import harness (counts); the Audit tap
san:discrepancyReported{ rows, flagged }the import harness (counts); the Audit tap
san:observationRecorded{ observationId, class, metric }the import harness (counts); the Audit tap
san:contextDeleted{ contextId }the import harness (counts); the Audit tap
san:zoneGeometrySet{ zoneId, lat, lng, source }the import harness (counts); the Audit tap
san:zoneGeometryImported{ matched, unmatched, source }the import harness (counts); the Audit tap
san:strategyCreated{ strategyId, code }the import harness (counts); the Audit tap
san:allocated{ allocationId, strategyId, zoneId, systemName, year }the import harness (counts); the Audit tap
san:deallocated{ allocationId, strategyId }the import harness (counts); the Audit tap
san:strategyBalanced{ strategyId, years, works, fleet }the import harness (counts); the Audit tap
san:strategyExported{ strategyId, markdown }the import harness (counts); the Audit tap

Review findings

  1. Every feature of the Suitability tab has a verb and a door: run, compare and export are buttons on the rail and the trail; screen, score and cost run inside close and are reached through it.
  2. Verbs without a door yet: alignRules (its surface is the Strategy area, step 5) and deriveContext on its own (the Contexts form calls it on save, step 4). Both are exercised by the engine proof until then.
  3. The evidence floor was declared but not enforced; it now is: close refuses a context whose gate measurements sit below survey.evidenceFloor, listing them, and the planner accepts them by an explicit switch on the rail that writes step 0 of the closing trail. The engine proof asserts the refusal.
  4. Configuration lived nowhere: the default policy, the closing defaults and the persistence of assessments were behaviour in code. They are now the service's contract, set through config.services.sanpath.options and read by the verbs.
  5. Tag was composed for no feature and is dropped from the loadout. Files is composed for the export's save door (step 4). Audit and Member are the frame's spine and stay.
  6. Roles are declared as data on the tabs and the rbac block; they gate on post-login and are inert on the auth-off sandbox. The engineer's edit rights on the registers (step 4) read the same roles.

A view composes shared bindings over the service's tables; it never builds a list or a form by hand, and it never computes. Each binding subscribes to its table's events and repaints itself; the view's own painters subscribe to selection and to the service bus. This tab lists, per view, the bindings the view requires, read from the service's register (the view reads its options from the same register, so the two cannot drift), the events each reacts to, and the option keys checked against what the shared binding actually reads. Then the event flow: every verb's event, who subscribes, and what a subscriber may do in turn; and the trace of one full cycle on the live surface, which is the proof that nothing runs away.

renderSites · control-stage; the rail lists sites, the survey form folded beneath; the stage reads map (central) · the variables as aligned rows · the surveys

BindingTableShared bindingDeclarative optionsFunctions beside the callReacts toPurpose
siteszonebindSelectEditor / bindSelector{"template": "list", "searchable": true, "pageSize": 8, "editor": "modal"}shape (name · unit · ward · category · households · latest verdict pill)zone events/selectpick the site (rail); the schema editor when the engineer edits
mapzonebindMap{"latField": "lat", "lngField": "lng", "categoryField": "recommendedClass", "draggable": true, "clickToPlace": true, "refreshOn": ["assessment", "allocation"]}shape (title · lat · lng · recommended class), moveFn and placeFn → setZoneGeometryzone events/select; markerDragEnd and canvasClickwhere the site is; a click places, a drag corrects (stage facet)
historycontextbindSelector{"template": "list", "pageSize": 6}where (surveys of the picked site; re-rendered on the pick), shape (label · surveyed · variables)context events/select; zone select by render()the surveys of the site (stage facet)

Painters (hand-composed residue) and what wakes them. variables: the site's variables as aligned rows: a fixed label column, every band strip the same width (ui-segmented-fill; the survey's input), a fixed tier column, one muted caption line of unit and cut points beneath · chips: zone select · context select/updateEntry · assessment/allocation createEntry · form: the survey form in the rail (uiForm) · bus: san:contextSaved → context.select

renderUnits · control-stage; the rail lists the five categories

BindingTableShared bindingDeclarative optionsFunctions beside the callReacts toPurpose
rangessystembindBoxPlot{"valueField": "value", "groupField": "category"}shape (category label · the chosen cost metric of the template)system resetData; the metric control by render()the ranges across categories, the central element
unitsunitbindSelector{"template": "list", "searchable": true, "pageSize": 8}where (the picked category), shape (unit · company · template · sites · capital)unit events/select; category pick by render()the company units of the category (stage facet)
templatessystembindSelector{"template": "list", "searchable": true, "pageSize": 8}where (the picked category), shape (name · components · cost · capital)system events/select; category pick by render()the catalogued templates of the category (stage facet)

Painters (hand-composed residue) and what wakes them. categories: a uiCollection list of the five classes with counts (the enum is schema, not data) · chips: category pick · unit/system/observation resetData · detail: the picked unit or template (unit select · system select)

renderSuitability · control-stage; the rail lists sites (the pick is shared with Sites)

BindingTableShared bindingDeclarative optionsFunctions beside the callReacts toPurpose
siteszonebindSelector{"template": "list", "searchable": true, "pageSize": 8}shape (name · households · category · verdict pill)zone events/selectpick the site (rail)
rowsByAsmassessmentbindChildTable{"child": "assessmentRow", "fkField": "assessmentId"}–assessment select/deselect → assessmentRow setScope/clearScopethe stage shows one run's options
optionsassessmentRowbindSelector{"template": "cards", "minWidth": 300, "pageSize": 16, "refreshOn": ["assessment"]}shape (system · verdict pill · fit, cost, capital · risks and concerns in words), sort (recommendation, then fit, then excluded, then ruled out)assessmentRow createEntry/resetData/select; assessment events through refreshOnthe options for the site, the central element
plotassessmentRowbindPlot{"template": "scatter", "xField": "cost", "yField": "fit", "groupBy": "verdict", "height": 260}shape (title · cost · fit · verdict label)assessmentRow createEntry/resetData (scope)fit beside cost (stage facet)
policiespolicybindSelector{"template": "compact"}shape (code · name · envelope · margin)policy resetData/selectassess under another policy (a door in How this was decided)

Painters (hand-composed residue) and what wakes them. follow: zone select → the site's latest run under the policy in force, else close() now (owner decision 2), else the named refusal · chips: assessment select · assessmentRow createEntry · why: assessmentRow select · how: assessment select · bus: san:assessmentClosed → assessment.select; san:allocated → chips

renderStrategy · sectioned control-stage

BindingTableShared bindingDeclarative optionsFunctions beside the callReacts toPurpose
strategiesstrategybindSelectEditor{"template": "list", "editor": "modal"}shape (name · code · target · envelope), onAddClick → createStrategystrategy events/selectpick or create the strategy (rail)
candidatesassessmentbindSelector{"template": "list", "searchable": true, "pageSize": 8, "ignoreScope": true, "refreshOn": ["allocation", "strategy"]}where (closed under the strategy's policy, zone not yet allocated), shape (context label · recommendation · zone)assessment events; allocation and strategy events through refreshOn; strategy selectwhat can be allocated (rail)
allocByStrategystrategybindChildTable{"child": "allocation", "fkField": "strategyId"}–strategy select → allocation scopethe stage shows one strategy's allocations
capitalByYearallocationbindPlot{"template": "bar", "xField": "year", "yField": "capital", "groupBy": "class", "height": 300}shape (year · capital · class)allocation createEntry/deleteEntry/resetData (scope)capital by year by class, the central element
allocationsallocationbindSelector{"template": "list", "pageSize": 10, "crud": {"delete": true}}shape (system · zone · year · households · capital), deleteFn → deallocateallocation events/selectthe allocations (stage facet)

Painters (hand-composed residue) and what wakes them. chips: strategy select · allocation createEntry/deleteEntry/resetData → strategyBalance · balances: the same, as chips per works and the fleet · document: strategyDocument → pre

renderRegister · control-stage; one register per rail section, one pane per kind on the stage

BindingTableShared bindingDeclarative optionsFunctions beside the callReacts toPurpose
sitescontextbindSelector{"template": "list", "pageSize": 10}where (contexts with an installed system), shape (label · installed · survives · overlap)context events/selectthe monitored sites of the back-test (rail)
observationsobservationbindSelectEditor / bindSelector{"template": "list", "pageSize": 8, "editor": "modal"}shape (class · metric · value · period · source), onAddClick → recordObservationobservation eventsthe monitored record, entered or imported (rail)
componentscomponentbindSelector{"template": "compact", "searchable": true, "pageSize": 10}shape (code · name · family)component resetData/selectthe catalogue by code (rail)
parametersparameterbindSelectEditor / bindSelector{"template": "list", "searchable": true, "editor": "modal", "pageSize": 8}shape (section · key · value · grade)parameter eventsthe register, editable by the engineer (rail)
policiespolicybindSelectEditor / bindSelector{"template": "list", "editor": "modal"}shape (code · name · margin · envelope)policy eventsthe policies, editable by the engineer (rail)
unitsunitbindSelectEditor / bindSelector{"template": "list", "searchable": true, "editor": "modal", "pageSize": 8}shape (unit · company · class · status)unit eventsthe units register, editable by the engineer (rail)
backtestRowscontextbindSelector{"template": "list", "pageSize": 16}where (installed), shape (site · installed · survives · raised vs recorded · J)context eventsthe back-test table (stage)
rulesrulebindSelector{"template": "list", "searchable": true, "pageSize": 8}where (rules of the picked component), shape (code on criterion = band · verdict · source)rule resetData; component select by render()every rule the picked component reads (stage facet)

Painters (hand-composed residue) and what wakes them. chips: context/observation events → backtest + discrepancyReport · discrepancy: the class × criterion table with the observed band and the flag (central) · site: the picked monitored site · component: the picked component · parameter: the picked parameter or policy

Option keys, checked

The platform's bindings read a fixed set of option keys and ignore the rest without a word (a known trap: an option the class never reads renders as if it were absent). The keys used above were checked against the keys each binding reads in publon.bind.js: bindSelector reads template, searchable, shape, sort, refreshOn, pageSize and its editing options; bindSelectEditor reads its own defaults and quickAdd and forwards the rest to the selector and the editor; bindPlot reads template, xField, yField, groupBy, groupColors, height and shape; bindChildTable takes the child and the foreign key. One dead key was found on this surface and removed: ownActions, which the cheat sheet still lists and no binding reads.

Event flow and circularity

Every mutating verb emits one colonised domain event after it has written (importers, close, deriveContext); the read verbs emit their result event too, so a surface can react without calling. Subscribers are of three kinds. The bindings react to table events (createEntry, updateEntry, deleteEntry, resetData, select) and only repaint. The painters of a view react to selection and to the service bus, and only select or repaint. The Audit tap records every service-bus event. No subscriber calls a verb, so no domain event can cause another: the only nesting the trace shows is the platform mirroring table events (select, deselect, resetData) onto the service bus inside the closed-run handler, which selects the new assessment; that is a mirror, not a loop. Two guards in the platform close the remaining doors: select on an already-selected row is a no-op, and setScope to the same scope emits nothing.

The two-parent trap was the one real circularity risk found: the platform auto-wires every reference as a parent-to-child scope and a child-to-parent selection, so a row with two parents could ping between them. The schema declares the join-only references (skip) and the cascade-free ones (cascade:false), and the trace asserts that selecting a system row selects no system and picking a context selects no zone.

Trace of one cycle on the live surface · 2026-09-04 07:09

ActionEvents counted (topic · count)Max nesting
pick context Z2svc:record:select 6 · svc:record:resetData 3 · svc:record:reset 3 · svc:assessment:resetData 2 · svc:assessment:reset 2 · svc:assessmentRow:select 2 · svc:assessment:select 2 · assessment:resetData 2 · assessment:record:reset 2 · svc:context:deselect 2 · svc:record:deselect 2 · svc:context:select 2 · context:filterChange 1 · svc:assessmentRow:resetData 1 · svc:assessmentRow:reset 1 · assessmentRow:select 1 · assessmentRow:record:select 1 · assessmentRow:resetData 1 · assessmentRow:record:reset 1 · assessment:select 1 · assessment:record:select 1 · context:deselect 1 · context:record:deselect 1 · context:select 1 · context:record:select 11
run assessment (P3)svc:record:createEntry 17 · svc:record:create 17 · svc:assessmentRow:createEntry 16 · svc:assessmentRow:create 16 · assessmentRow:createEntry 16 · assessmentRow:record:create 16 · assessmentRow:dbSync 16 · svc:record:select 4 · svc:policy:select 2 · svc:assessmentRow:resetData 2 · svc:assessmentRow:reset 2 · svc:record:resetData 2 · svc:record:reset 2 · assessmentRow:resetData 2 · assessmentRow:record:reset 2 · svc:assessment:deselect 2 · svc:record:deselect 2 · svc:assessment:select 2 · policy:select 1 · policy:record:select 1 · svc:assessment:createEntry 1 · svc:assessment:create 1 · assessment:createEntry 1 · assessment:record:create 1 · assessment:deselect 1 · assessment:record:deselect 1 · assessment:select 1 · assessment:record:select 1 · svc:san:assessmentClosed 1 · assessment:dbSync 12
select a system rowsvc:assessmentRow:deselect 2 · svc:record:deselect 2 · svc:assessmentRow:select 2 · svc:record:select 2 · assessmentRow:filterChange 1 · assessmentRow:deselect 1 · assessmentRow:record:deselect 1 · assessmentRow:select 1 · assessmentRow:record:select 11
compare policiessvc:san:policiesCompared 11
tab away and back0

Bindings per table before and after a tab switch: {"context": 2, "policy": 1, "assessment": 2, "assessmentRow": 2} → {"context": 2, "policy": 1, "assessment": 2, "assessmentRow": 2}. Failures: 0. The proof is Tests/sanpath-bus-trace.mjs; the obligation that a closed run reaches the surface is declared in the platform's wiring register (Tests/wiring-review.mjs), which fails the estate's gate if the subscriber is ever removed.

The first build (3–4 September) shipped six tabs derived from the method's steps — Map · Catalogue · Contexts · Decision · Strategy · Validation — and the owner, reading it, called it "a bit too vague … information wading for the sake of it", and said what he expected instead: for a given site, the characterisation and the values of the variables at that site; on another tab, metrics about the units for the different companies, and the metrics and ranges for the categories of product; on another, the suitability of a site across the technology options, with the estimated costs, risks and concerns. The difference between that and the build, and the principles it teaches, are recorded here as part of building it better; the full ledger is PublonCore/tasks/todo-sanpath-rework.md.

The first build against the three questions

Tab (first build)What it showedQuestion servedThe gap
Mapzones as points; the picked zone's chips1, partlywhich sites exist and where, but no characterisation: a second tab for the variables
Contextszone → the survey as a band strip; a gates preview; the history; the form1the characterisation existed but was named for the engine (contexts, survey, bands); the gates preview was a fragment of question 3 inside question 1
Cataloguetemplates, components, parameters, policies — four rail sections over one stage2, partlytemplates one at a time, never categories with ranges; no company units; the engine's internals in front of the reader; one pane serving four kinds, so a click on a component emptied the cost and fit values (the defect reported)
Validation (engineer)monitored sites with their installed unit, uptime per class, back-test, discrepancy report2where the company units actually lived — behind the engineer role, framed as calibration
Decisioncontext + policy → run → plot, systems, deciding rules, trail3suitability and cost present; risks and concerns one click deeper per system, worded as rules; a policy had to be understood before anything showed
Strategyallocations, capital by year, balances, document–a later step at the same level as the questions

In one sentence. The tabs were derived from the engine's steps, not from the reader's questions: every question was spread over two tabs, every tab mixed two questions, and the vocabulary was the engine's. What the meta plan promised and the build skipped: "provider units attached to a system; benchmark record per class" — question 2 had no table to stand on until the company and unit tables of 4 September.

The principles (now in the platform's metadesign fundamentals)

  1. Tabs are questions. One tab per question the reader brings, in the order they ask them; named for the question's subject (Sites · Units · Suitability), never for the engine's step.
  2. A pick answers its question whole. Selecting a record fills the stage with everything that question needs, within the event: no second click, no second tab, no pane whose meaning depends on which rail section is open. A pane that has shown a value never goes blank because of a pick elsewhere.
  3. One rail, one kind. The control column lists one kind of record; four kinds in one rail make the stage ambiguous, and ambiguity is what "vague" names.
  4. Values before bands, words before rules. The measured value with its unit and band; risks and concerns in the reader's words; the rule, document and grade one click deeper as evidence.
  5. Categories are metrics and ranges, not lists. A category is shown by its members' metrics and their ranges.
  6. The engineer's world is a separate door. Calibration surfaces sit behind the engineer role on their own tab and never shape the reader's tabs.
  7. A later step is a later tab, or a door from the answer. The portfolio follows the verdict and is reached from it.

The rework, decided 4 September

Sites (the map folded in as the site's location) · Units (new: the companies' units and the five categories with their ranges; the company and unit tables, the field record's four units as the first register) · Suitability (the options as cards with risks and concerns in words; a site with no run is assessed on the pick under the policy in force; the doors to another policy, export and allocation) · Strategy, kept as the planner's later step · Register, the engineer's door (the old Catalogue internals and Validation, one kind per section, one pane per kind). Every surface is proved by Tests/sanpath-selection.mjs (a pick drives the stage), sanpath-sites.mjs and sanpath-suitability.mjs (the round trips), sanpath-smoke.mjs (every tab filled, zero console errors) and sanpath-bus-trace.mjs (the bus: one event per verb, no loop).

Each step is complete when its round trip runs on real data, driven through the interface, with the reference implementation and the platform agreeing before the next step begins. Nothing is seeded: the importers read the registers this page publishes, and every context a proof creates is the case-study or back-test context of this page.

  1. Schema and importers — done 3 to 4 September 2026. The twelve tables; importers for the rule register (26 components, 13 criteria, 309 register rows expanded per component), the systems, the parameters, the policies, the zone register (563 settlements) and the works register (27 works), each idempotent on its natural key. Proof: twelve checks including a second run that inserts nothing and a read-back over the wire.
  2. Engine — done 4 September 2026. Seven verbs reading tables only; every result carries the ids of the rules and parameters it read. Proof: thirty-six checks against the acceptance file, the three archetypes under four policies to the same decisions, fits and costs, the five back-test verdicts, the alignment matrix, persistence over the wire.
  3. Decision surface — done 4 September 2026. The control-stage described under Areas. Proof: twelve checks driven through the interface, from picking a context to reloading and finding the run again, screenshots read, zero console errors.
  4. Contexts and catalogue surfaces — done 5 September 2026. The survey enters through a form in the rail and a band strip on the stage (a segmented control per criterion with a tier select), saved through one verb and derived at once; what the bands decide is shown beside the zone's surveys. The catalogue shows each system's chain, the rules that touch it, its cost and fit values; the registers are editable by the engineer. Proofs: the survey round trip (save, derive, find on the Decision rail, reload, delete) and the catalogue walk, both zero console errors.
  5. Strategy and map hub — done 5 September 2026. A strategy is a named plan under one policy with an envelope and a horizon; a zone is allocated the system its closed assessment recommends, in a year of the horizon; capital by year by class is the central element; the balances read each works' headroom against the sewered households drawn on it and the desludging fleet against the emptying events the allocations imply (register section F, five assumed parameters); the strategy document exports. The map hub composes the map binding over the zone register and shows a loud named state until the register carries latitude and longitude. Proof: the strategy round trip (create, candidates, allocate, chips and plot, document, refusals, reload, deallocate) with zero console errors.
  6. Rework to the reader's questions — done 4 September 2026. The six engine-step tabs became Sites · Units · Suitability · Strategy · Register (engineer); the map folded into Sites as its central element, the variables as aligned rows beneath it (5 September); company and unit tables from the de-risking field record; option cards with risks and concerns in words; a site assessed on the pick; Save to Files on both export doors; the artefact readable inside the system's About tab. Proofs: sanpath-smoke, sanpath-selection, sanpath-sites, sanpath-suitability, sanpath-files, sanpath-bus-trace. The comparison and the principles are the Rework tab.
  7. Sign-off of the grade C rules and the fit values — done 5 September 2026 (owner). Recorded in section A; register version 2026-09-05; the importers update held rows, so both hosted instances took the change by provisioning and the demo world re-closed under it.
  8. Validation harness — done 5 September 2026. A context may carry an installed system and its hazard-register categories; the back-test screens it and compares the raised categories with the recorded ones (J and J_S). Observations of a class over a period feed the discrepancy report, which bands the observed value and flags every operating-risk criterion that differs from the band by the trigger; the engineer changes the register, nothing changes itself. Proof: on the demo world, five monitored sites, all surviving, mean J 0.37, ten criteria flagged for review.
  9. Demo world — done 5 September 2026. The illustrative world is BUILT THROUGH THE VERBS on a demo backend, never seeded: the real registers, eight synthetic zones with points scattered round Durban, the three archetype surveys and the five monitored sites as contexts, every closing under every policy, one strategy with three allocations, an observed record per class. Idempotent; a second build inserts nothing. Every area is walked on it by a driven proof with screenshots read.
  10. Pilot — three eThekwini zones profiled by municipal staff through the form, assessed and closed on the platform; the protocol and the register republished in the form the pilot leaves them. Hosting alongside the InfraTrack solo instance, accounts for Pinky's team, the zones EWS names, the GIS layer from EWS — decided 5 September.
Behind the path

How it is built, and where it goes next

The five steps above are the whole of the selection method. What follows is the machinery behind them and what a municipality does after a single assessment. Each is folded because none of it is needed to follow the path.

Rules are data, written from primary sourceswhy the screen can be audited

A rule is a row: target (a component family or one component), criterion, band, verdict, condition, source, grade. The register is written by hand from the documents named in section A, and an exporter turns it into rows the platform imports, expanding each family rule to the members of the family. The evaluation knows how to look up a band, apply a rule, take the worst verdict over a chain and sum a weighted score. It knows nothing about septic tanks, so every verdict traces to a row and its document, and a revision of a standard is an edit to the rows that cite it, not a rewrite.

From the register to rule rows (soak pit, percolation)
targetcriterionbandverdictconditionsourcegrade
soakpercolationimpermeablefail—SANS 10252-2: no soakaway below the minimum percolation rateA
soakpercolationvslowcondenlarged soakaway or leach field sized from the percolation testSANS 10252-2A
soakpercolationvfastfail—DWS03: rapid infiltration to groundwaterA
soakpercolationfastcondgroundwater risk re-assessed; setback from abstractionDWS03A
soakpercolationmoderatepass—SANS 10252-2A
soakpercolationslowpass—SANS 10252-2A
On the live system · the same rows, read from the register
The soak pit's rules on the Register tab: the percolation bands with their verdicts and conditions, each citing SANS 10252-2 or the Groundwater Protocol, as the engineer reads and edits them.
The soak pit's rules on the Register tab: the percolation bands with their verdicts and conditions, each citing SANS 10252-2 or the Groundwater Protocol, as the engineer reads and edits them.
Conditions become obligations in the de-risking programmeselection and verification on one loop

A condition raised at selection becomes a cost line where it has a price and a de-risking register entry where it has a risk. The programme checks that entry at commissioning, and the monitored outcome of the site, uptime and time within specification per quarter, feeds back into the operating-risk scores by system class and context band. A system whose conditions were not met and then failed in the field is the model's calibration signal.

One loop
Zone contextmeasurements Registerbands · rules · weights Screen and ranksteps 3 and 4 Recommendationrank + conditions Installed sitecommissioned De-risking registerconditions → HAZOP entries InfraTrack outcomesuptime · % in spec checked outcomes by class and band calibrate the operating-risk scores
On the live system · conditions raised against the hazard register
The monitored site Ekuthuleni (a communal WESS) on the Register tab: the conditions the screen raises for the installed system, each assigned to a hazard category, beside the categories the site's de-risking register actually recorded; the overlap is the back-test's score.
The monitored site Ekuthuleni (a communal WESS) on the Register tab: the conditions the screen raises for the installed system, each assigned to a hazard category, beside the categories the site's de-risking register actually recorded; the overlap is the back-test's score.
From one site to a municipal portfolioshared capacity, budget, homogeneity

Run across a municipality's zones, the assessments compose into a portfolio, and the portfolio adds three constraints a single site never sees. A works with headroom for two thousand households cannot take sewer allocations from every zone within reach, so treatment capacity, desludging fleet and disposal sites are shared resources that allocations consume in sequence. Capital sums against the budget envelope by year, and phasing is the schedule that fits while reaching a named count of sites operating within specification by a named date. And a municipality will not run eleven systems, so the count of classes allocated and the operating capacity each demands stays visible.

A shared resource consumed in sequence (illustrative)
Works headroom: 2,000 households Zone A · 600 Zone B · 900 Zone C · 700 limit Balance after A and B: 500. C needs 700. C → DEWATS, on site
On the live system · the portfolio on the Strategy tab
The demo strategy under P1: three zones allocated, households served, capital committed against the envelope; capital by year; the shared resources (works headroom against draw, the desludging fleet against events) and the picked allocation's detail with the run it rests on.
The demo strategy under P1: three zones allocated, households served, capital committed against the envelope; capital by year; the shared resources (works headroom against draw, the desludging fleet against events) and the picked allocation's detail with the run it rests on.
The demo strategy under P1: three zones allocated, households served, capital committed against the envelope; capital by year; the shared resources (works headroom against draw, the desludging fleet against events) and the picked allocation's detail with the run it rests on.
The demo strategy under P1: three zones allocated, households served, capital committed against the envelope; capital by year; the shared resources (works headroom against draw, the desludging fleet against events) and the picked allocation's detail with the run it rests on.
One engine on the platforma refactor of the InfraTrack suitability service, not a twin

The platform's suitability service already runs a two-phase match for InfraTrack, with thirteen gates and twelve factors written as code and binary verdicts. The path above is that engine with three changes: rules read from the register instead of code, three-valued verdicts, and systems as chains. InfraTrack's technology profiles become one-component chains, nothing it does today changes, and its matching becomes auditable at the same time. The build is therefore the register, the importer and the surfaces.

What changes
TODAY InfraTrack Suitability enginerules in codebinary verdicts AFTER InfraTrack Framework One engineband · rule · worst · sumthree-valued · chains reads Criteria registerbands · lookups · weights Rule tablecomponent × band → verdict
Sources

References

Works cited on this page, with the municipal documents the framework reads as inputs. The white paper carries the full list.

  1. Chandarman, D. (2026). Application of bipartite matching algorithms to industrial symbiosis: pairing consumers and producers in sugar production. MSc dissertation, University of KwaZulu-Natal, under examination.
  2. Crous, P., Haarhoff, J. and Buckley, C. A. (2013). Water demand characteristics of shared water and sanitation facilities: Experiences from community ablution blocks in eThekwini Municipality, South Africa. Water SA 39(3).
  3. Daudey, L. (2018). The cost of urban sanitation solutions: a literature review. Journal of Water, Sanitation and Hygiene for Development 8(2), 176–195. doi:10.2166/washdev.2017.058
  4. Department of Water and Sanitation (2023). Green Drop Progress Assessment Tool Report 2023. Pretoria: Department of Water and Sanitation.
  5. eThekwini Municipality (2025). Draft Sanitation Policy (Trading Services).
  6. eThekwini Municipality (2026). Integrated Development Plan 2026/27 Annual Review, with Appendix 12: eThekwini Informal Settlements.
  7. eThekwini Water and Sanitation (2024). Service Level Standards, 18th edition.
  8. eThekwini Water and Sanitation (2025). Ten-year sanitation plan, municipal planning document, November 2025.
  9. Gambrill, M., Gilsdorf, R. J. and Kotwal, N. (2020). Costs, Climate and Contamination: Three Drivers for Citywide Sanitation Investment Decisions. Frontiers in Environmental Science 8, 130. doi:10.3389/fenvs.2020.00130
  10. Graham, P. M., Pattinson, N. B. and Still, D. (2025). The state of wastewater management in South Africa: data gaps, missing wastewater, and Green Drop reporting. Water SA 51(2).
  11. ISO (2025). ISO 30500:2025 Non-sewered sanitation systems: Prefabricated integrated treatment units. General safety and performance requirements for design and testing. International Organization for Standardization.
  12. Lohman, H. A. C., Morgan, V. L., Li, Y., Zhang, X., Rowles, L. S., Cook, S. M. and Guest, J. S. (2023). DMsan: A Multi-Criteria Decision Analysis Framework and Package to Characterize Contextualized Sustainability of Sanitation and Resource Recovery Technologies. ACS Environmental Au 3(3), 179–192. doi:10.1021/acsenvironau.2c00067
  13. Mitra, A., Narayan, A. S. and Lüthi, C. (2022). Sanitation potpourri: Criteria for planning mix of sanitation systems for citywide inclusive sanitation. Environment and Planning B: Urban Analytics and City Science 49(8), 2195–2215. doi:10.1177/23998083221091568
  14. Mkhize, N., Taylor, M., Udert, K. M., Gounden, T. G. and Buckley, C. A. (2017). Urine diversion dry toilets in eThekwini Municipality, South Africa: acceptance, use and maintenance through users' eyes. Journal of Water, Sanitation and Hygiene for Development 7(1), 111–120. doi:10.2166/washdev.2017.079
  15. Ntombela, C., Funke, N., Meissner, R., Steyn, M. and Masangane, W. (2016). A critical look at South Africa's Green Drop Programme. Water SA 42(4). doi:10.4314/wsa.v42i4.21
  16. Olschewski, A. and Casey, V. (2015). The Technology Applicability Framework: A Participatory Tool to Validate Water, Sanitation, and Hygiene Technologies for Low-Income Urban Areas. Technologies for Development. doi:10.1007/978-3-319-16247-8_18
  17. Ramôa, A. R., McConville, J., Lüthi, C. and Matos, J. S. (2018). Use of process guides for comprehensive urban sanitation technology decision-making: practice versus theory. Water Policy 20(1), 158–174. doi:10.2166/wp.2017.117
  18. Ross, S., Fane, S. and Foster, T. (2024). Comparative economic analysis of urban sanitation interventions in low- and middle-income countries: a systematic review. Journal of Water, Sanitation and Hygiene for Development 14(9), 794–807.
  19. Sainati, T., Zakaria, F., Locatelli, G., Sleigh, P. A. and Evans, B. (2020). Understanding the costs of urban sanitation: towards a standard costing model. Journal of Water, Sanitation and Hygiene for Development 10(4), 642–658. doi:10.2166/washdev.2020.093
  20. Salisbury, F., Brouckaert, C., Still, D. and Buckley, C. (2018). Multiple criteria decision analysis for sanitation selection in South African municipalities. Water SA 44(3). doi:10.4314/wsa.v44i3.12
  21. Schrecongost, A., Pedi, D., Rosenboom, J. W., Shrestha, R. and Ban, R. (2020). Citywide Inclusive Sanitation: A Public Service Approach for Reaching the Urban Sanitation SDGs. Frontiers in Environmental Science 8, 19. doi:10.3389/fenvs.2020.00019
  22. Shyu, H. Y., Bair, R. A., Castro, C. J., Xaba, L., Delgado-Navarro, M., Sindall, R., Cottingham, R., Uman, A. E., Buckley, C. A. and Yeh, D. H. (2021). The NEWgenerator non-sewered sanitation system: Long-term field testing at an informal settlement community in eThekwini municipality, South Africa. Journal of Environmental Management 296, 112921. doi:10.1016/j.jenvman.2021.112921
  23. Spuhler, D. and Lüthi, C. (2020). Review of frameworks and tools for urban strategic sanitation planning: considering technology innovations and sustainability. Journal of Water, Sanitation and Hygiene for Development 10(4), 768–785. doi:10.2166/washdev.2020.062
  24. Spuhler, D., Germann, V., Kassa, K., Ketema, A. A., Sherpa, A. M., Sherpa, M. G., Maurer, M., Lüthi, C. and Langergraber, G. (2020). Developing sanitation planning options: A tool for systematic consideration of novel technologies and systems. Journal of Environmental Management 271, 111004. doi:10.1016/j.jenvman.2020.111004
  25. Strande, L. (2024). Integrating recent scientific advances to enhance non-sewered sanitation in urban areas. Nature Water 2, 405–418. doi:10.1038/s44221-024-00240-7
  26. Tilley, E., Ulrich, L., Lüthi, C., Reymond, P. and Zurbrügg, C. (2014). Compendium of Sanitation Systems and Technologies. Eawag.
  27. WASH R&D Centre, University of KwaZulu-Natal (2026). WESS Engineering De-Risking Protocol: reference report, with the Water Research Commission.
  28. World Health Organization (2018). Guidelines on Sanitation and Health. Geneva.
  29. World Health Organization (2022). Sanitation Safety Planning: Step-by-step risk management for safely managed sanitation systems. Geneva.