Skip to content

quantities Module — Formula Reconciliation

§1 Purpose

This document is an independent reconciliation of the quantities module spec (quantities-spec.md). It was produced in a separate sub-chat from the spec itself, with access to the spec output but not to the source workbook during the initial pass. Its purpose is to:

  1. Apply the two-axis verdict scheme (see PROJECT.md decision #23) to every formula in the spec, assigning each a VALIDATED or CORRECTED verdict.
  2. Identify discrepancies between the spec's transcription and what a correct implementation of the stated engineering intent would produce.
  3. Assign provenance status (SOURCED / EXPERT-JUDGEMENT / BLOCKED) to every parameter.
  4. Produce the divergence fixtures used by the Python test suite to assert that corrected formulas diverge from the spec by the documented amount.

The spec (quantities-spec.md) is the requirements artifact — it records what the Excel does, bugs included. This document is the judgment layer — it records what the Python module should do, and why.


§2 Method

  1. The spec was read in full, including the Errors & inconsistencies section (E1–E22) and the Parity fixtures.
  2. Each formula was assessed against: (a) internal consistency with sibling formulas in the same sheet; (b) the stated engineering intent in the description column; (c) normal practice for the construction technique described.
  3. Where the spec's transcription was internally consistent with the rest of the sheet, even if the underlying value was unsourced, the verdict is VALIDATED — parity is enforced at 0.1%.
  4. Where the formula structure is demonstrably wrong (wrong-row reference, missing parentheses, decimal-point slip, missing formula, transposed values, wrong geometric calculation), the verdict is CORRECTED — the Python module must diverge, a divergence test asserts the expected difference, and the normative basis for the correction is cited.
  5. Findings not captured in the spec's E1–E22 list were flagged for GitHub issues.
  6. Every parameter was assessed for provenance. BLOCKED parameters receive no default and the module raises ValueError — the gap must be audible in the code.

§3 Formula verdicts

VALIDATED formulas (parity enforced at 0.1%)

These formulas are internally consistent with their stated intent and with sibling rows. The Python implementation must reproduce the Excel output to within 0.1%.

Row Item Formula verified against Note
5 A.III.1 (layer 1) Internal consistency; D5 formula matches stated layer fractions E2 (0.21 vs 0.20) reproduced as-is
6 A.III.1 (layer 2) — materials other than H6/I6 See §4.2 for transposition verdict L6, K6, G6 are VALIDATED; H6/I6 are CORRECTED
7 A.III.2 Consistent 150 kg/m³ blinding concrete recipe
8 A.III.3 ml × 1 conversion documented and correct
9 A.III.4 Canonical 350 kg/m³ recipe with rebar
11 A.IV.1 Same 350 kg/m³ recipe as row 9
12 A.IV.2 Same 350 kg/m³ recipe as row 9
14 A.V.1 Adobe wall formula internally consistent
15 A.V.2 BBSC header row; rock-only model preserved ✓ parity; but see §4.5 on BBSC
16 K16 E3 (wrong-row reference) — reproduce E3 as written K16 = D15 × ...
17 A.V.4 38 cm wall with BBSC
18 A.V.5 38 cm wall, no BBSC
19 A.V.6 20 cm wall
21 A.VI.1 Arch, correct parentheses
22 A.VI.2 Arch, correct parentheses
23 A.VI.3 Arch with gravel footing term
24 J24, K24 E4 (missing outer parentheses) — reproduce E4 as written
25 A.VI.4 (row 25) Correctly parenthesised
26 A.VI.5 Correctly parenthesised
27 A.VI.6 Large opening, same pattern
32 K32 E6 (0.043 vs 0.0043) — reproduce E6 as written 7.6× water overstatement; preserved
33 A.VIII.2 Correct coefficient
35 A.IX.1 Roof waterproofing slope
36 U36 E9 (hardcoded 289.15) — reproduce E9 as written Negligible drift
38 J38, K38 E5 (J38 missing outer parens, K38 correct) — reproduce E5 as written
41 B.I.1 16 mm cement plaster; complete formula
42 B.I.2 Earth-sand-gravel-tar roof coating (E14: gravel silently absent) — reproduce E14
43 B.I.3 16 mm cement plaster; complete
44 B.I.4 Earth-sand plaster on vaults
45 B.I.5 E13 (missing cement) — reproduce E13 as written L45 formula absent
46 B.I.6 E13 same — reproduce E13 L46 absent
47 B.I.7 E13 same — reproduce E13 L47 absent
50 B.II.1.a Compacted earth fill, correct
53 H53 E10 (width 0.45 vs 0.35) — reproduce E10 as written
53 I53, K53, L53 Correct width 0.35
55 B.II.3.a 250 kg/m³ window-sill concrete; correct
57 B.II.4.a Slope earth, correct
60 N60, O60 E11 (0.2×0.9 perimeter) — reproduce E11 as written
61 B.III.1.b Single-leaf louvered window; correct
63 N63, O63 E20 (3.2 vs 3.12 m) — reproduce E20
64 N64 E12 (2.7 and 2.3 factors) — reproduce E12 as written
64 O64 Uses correct 2.79
65 B.III.2.c Metal partition door; correct
67 B.III.3.a Metal gutter; correct
69 B.IV.1 Wall paint coverage correct
70 B.IV.2 Vault paint coverage correct
71 B.IV.3 Antirust paint; flat-rate per unit
72 B.IV.4 Tyrolean plaster; density-conversion formula correct
74 B.V.1 Floor tiling + 10% waste
75 B.V.2 Tile skirting
76 B.V.3 Faience tiling

CORRECTED formulas (Python must diverge; divergence tests in backend/tests/fixtures/quantities_divergence.py)

ID Row / col Correction Normative basis Divergence from spec
C1 H6, I6 Sand and gravel columns are transposed: H6 should be sand (= D6 × 0.53 × 0.21), I6 should be gravel (= D6 × 0.75 × 0.21). See §4.2. Normal concrete-mix practice: gravel > sand by volume in any standard mix design. Marco confirmed: H6 cached value = 4.34 m³ (labelled gravel), I6 = 6.15 m³ (labelled sand) — sand exceeds gravel, which is not physically possible in a w/c-ratio-consistent mix. Gravel total ↑ by (D6 × (0.75−0.53) × 0.21) = 1.804 m³; Sand total ↓ by same
C2 J29, J30 Vault arc length formula uses π × span (full circumference for a circle of radius = span). Correct half-arc is π × span/2. See §4.3. Geometry: a Nubian vault is a semicylinder; its wall cross-section brick arc is a half-circle of radius = span/2. Arc length = π × r = π × span/2, not π × span. Earth total ↓ by ~78.9 m³ (−9.5% of project total 830.5 m³)
C3 M51 Rebar formula entirely absent from row 51 ("Reinforced concrete slab, 300 kg/m³"). See §4.1. EN 15804+A2 §6.3.3: "all significant materials and components shall be included." A 100 mm RC slab without rebar is structurally incomplete. Normative rebar density requires Chiwara attribution — see §6, BLOCKED parameter. Steel Rebars total understated. Magnitude depends on BLOCKED mesh spec.
C4 T60, T63, T64 Glass not multiplied by window count D. See §4.4. Quantity principle: a formula applying to N identical units must be scaled by N. The current formulas compute glass for one window type, regardless of count. Glass total understated by factor ≈ (Σ D_i - 1) across three glass rows. See §4.4 for exact values.
C5 U36 Anti-termite treatment quantified off roof area (D35 = 289.15 m²). See §4.5. EN 15804+A2 scope: treatment refers to foundation zone. Correct metric is foundation contact area or treated perimeter, not roof area. Requires Chiwara attribution for the correct reference area — see §6, EXPERT-JUDGEMENT. Direction: treatment volume overstated if foundation area < roof area; understated if foundation perimeter × penetration depth > 5 L/m² × roof.

§4 Correction detail

§4.1 — Row 51: Missing rebar formula (+163% project steel rebar, BLOCKED)

Finding: B.II.1.b (row 51) is a 100 mm reinforced concrete slab at 300 kg/m³. The spec transcribes formulas for Gravel, Sand, Water, and Cement but no Steel Rebars formula (column M). The project total for Steel Rebars (1330.6 kg) derives entirely from rows 9, 11, and 12 (350 kg/m³ isolated footings and RC columns/beams).

Engineering assessment: A 100 mm structural slab without reinforcement is not compliant with any standard structural concrete design. Rebar (or mesh) is always present. The omission is a missing formula, not a deliberate choice — the spec's Errors table (E13) already identifies the analogous omission of cement for plastering rows 45/46/47 as an error of the same type.

Magnitude: If the same rebar density as the 350 kg/m³ recipe (100 kg/m³) were applied naively: 21.702 m³ × 100 kg/m³ = 2170.2 kg. That would increase total Steel Rebars from 1330.6 kg to 3500.8 kg, an increase of 163%. However, mesh for a 100 mm slab is specified differently from structural rebar — the correct density is a BLOCKED parameter requiring Chiwara team attribution. See §6.

Verdict: CORRECTED. The Python module must include a rebar/mesh formula for row 51. The parameter is BLOCKED pending §6 attribution. The module raises ValueError until the mesh spec is supplied.

Divergence test: See backend/tests/fixtures/quantities_divergence.py::test_c1_slab_rebar_blocked.


§4.2 — Row 6: Sand/gravel transposition (confirmed by Marco)

Finding: Row 6 (A.III.1, second layer — 250 kg/m³ cyclopean concrete) has: - H6 = D6 × 0.53 × 0.21 (column H = Gravel, factor 0.53) - I6 = D6 × 0.75 × 0.21 (column I = Sand, factor 0.75)

Marco confirmed the cached cell values: H6 = 4.34 m³ (gravel), I6 = 6.15 m³ (sand). Sand (6.15 m³) exceeds gravel (4.34 m³), which is anomalous: in any standard concrete mix (including the other two mix designs in this sheet — 350 kg/m³ rows 9/11/12 and 300 kg/m³ row 51), gravel volume exceeds sand volume. The 250 kg/m³ mix design in rows 55 (window sills) uses H=0.75 and I=0.53 — the opposite assignment from row 6. This confirms that columns H and I are transposed in row 6.

Correct formulas: - H6 = D6 × 0.75 × 0.21 (gravel at the larger 250 kg/m³ proportion) - I6 = D6 × 0.53 × 0.21 (sand at the smaller proportion)

Magnitude: - Gravel change: D6 × (0.75 − 0.53) × 0.21 = 39.037 × 0.0462 = 1.804 m³ (increase) - Sand change: same magnitude, decrease - Project-level impact: Gravel total 31.06 → 32.86 m³ (+5.8%), Sand total 56.05 → 54.25 m³ (−3.2%)

Normative basis: Internal consistency (sibling row 55 uses 0.75 gravel / 0.53 sand for the same 250 kg/m³ design); confirmed by Marco.

Divergence test: test_c2_row6_sand_gravel_transposition.


§4.3 — Nubian vault arc: π × span vs π × span/2 (−9.5% project earth)

Finding: Row 29 (A.VII.1): J29 = 18.6 × (3.14 × 3.3) × 0.25. Row 30 (A.VII.2): J30 = D30 × (2.6 × 3.14) × 0.25.

The spec annotates this as "semicircle arc length for a 3.3 m-radius vault (π·r)". But:

  • A Nubian vault with span s is a semicylinder. The brick course arc is a half-circle whose diameter = span. Radius = span/2. Arc length = π × (span/2).
  • The formulas use π × span (i.e. π × diameter), which equals the full circumference of the semicircle's circle — twice the half-arc.

This doubles the earth volume computed for both vault rows compared to the physically correct half-arc.

Correct formulas: - J29 = D29 × (3.14 × 3.3/2) × 0.25 = D29 × 5.181 × 0.25 - J30 = D30 × (3.14 × 2.6/2) × 0.25 = D30 × 4.082 × 0.25

Magnitude (using spec quantities D29 = 18.6 ml, D30 = 53.4 ml): - Row 29 spec: 18.6 × 10.362 × 0.25 = 48.18 m³. Corrected: 18.6 × 5.181 × 0.25 = 24.09 m³. Difference: −24.09 m³. - Row 30 spec: 53.4 × 8.164 × 0.25 = 108.99 m³. Corrected: 53.4 × 4.082 × 0.25 = 54.50 m³. Difference: −54.49 m³. - Total earth decrease: −78.58 m³ out of spec total 830.49 m³ = −9.5%.

Note: K29 (J29 × 0.2585) and K30 (as written: D30 × 0.2585, which is E8) also change. K29 is derived from J29 so it follows automatically. K30's E8 bug is preserved separately.

Normative basis: Geometry. A half-circle of span s has radius s/2; the arc subtended by a semicircle is π × r = π × s/2.

Divergence test: test_c3_vault_arc_half_circle.


§4.4 — Glass not multiplied by window count

Finding: Rows 60, 63, 64 each have a glass formula (T60, T63, T64) that computes the glass volume for a single rounded fanlight — not scaled by the line's unit count D.

  • T60 = 1/2 × 0.45² × π × 2 × 0.004 (hardcoded constant, not scaled by D60 = 17)
  • T63 = 1/2 × 0.6² × π × 2 × 0.004 (not scaled by D63 = 2)
  • T64 = 1/2 × 0.45² × π × 2 × 0.004 (not scaled by D64 = 2)

The spec classifies this under Open Questions (OQ6) and notes "glass is being counted per distinct opening type, not per unit count D". The reconciliation verdict is unambiguous: a BoQ line for 17 windows must contribute 17 windows' worth of material, not 1.

Correct formulas: - T60 = D60 × (1/2 × 0.45² × π × 2 × 0.004) = 17 × 0.001272 = 0.021634 m³ - T63 = D63 × (1/2 × 0.60² × π × 2 × 0.004) = 2 × 0.002262 = 0.004524 m³ - T64 = D64 × (1/2 × 0.45² × π × 2 × 0.004) = 2 × 0.001272 = 0.002544 m³

Magnitude: - Spec Glass total = 0.0096084 m³ (3 hardcoded values summed) - Corrected Glass total = 0.021634 + 0.004524 + 0.002544 = 0.028702 m³ - Difference: +199% (≈ 3×)

Normative basis: Basic quantity principle — a formula for N identical items is scaled by N.

Divergence test: test_c4_glass_scaled_by_count.


§4.5 — Anti-termite treatment referenced to roof area

Finding: U36 = 1 × 5 × 289.15, where 289.15 is a rounded copy of D35 (roof waterproofing area). The rate 5 L/m² is stated in the sheet. But anti-termite treatment is applied to the foundation zone (soil under and around the slab), not to the roof. Using roof area as the proxy for foundation area is methodologically unsound.

Verdict: CORRECTED. Requires Chiwara team attribution for the correct reference area (foundation plan area, foundation perimeter × treatment depth, or a project-specific survey). Until attributed, the parameter is EXPERT-JUDGEMENT (pending) — see §6.

Divergence: Direction and magnitude depend on the ratio of foundation contact area to roof area (289.15 m²). If foundation plan area ≈ roof area (common in compact school layouts), the numeric divergence may be small. The correction is methodological, not primarily numeric.

Divergence test: test_c5_anti_termite_area_attribution (flagged XFAIL pending §6 resolution — the test exists but cannot pass until the reference area is attributed).


§5 Summary verdict table

Axis Status Count Action
VALIDATED Parity ≤ 0.1% enforced ~50 formula cells Regression test against spec Fixture 4
CORRECTED Python diverges; divergence test asserts expected Δ 5 corrections (C1–C5) quantities_divergence.py
SOURCED (parameter) Normative citation available 0 in workbook (all are UNKNOWN in the source) Phase 1 Step 2: attribution sprint
EXPERT-JUDGEMENT (parameter) Chiwara practitioner data, permitted with attribution Multiple (anti-termite area, steel density for carpentry, OMPU source, sand density scope) See §6
BLOCKED (parameter) Neither normative source nor attributed data 2: slab mesh spec; BBSC composition Module raises ValueError — no placeholder

§6 Attribution stubs (extracted to chiwara-attribution-requests.md)

The full text of the attribution requests is in docs/methodology/chiwara-attribution-requests.md. Summary:

Parameter Status Owner Blocker?
Slab mesh spec (row 51 rebar density for 300 kg/m³ slab) BLOCKED Chiwara / site engineer Yes — module raises until resolved
BBSC composition (binder silently missing from LCA) BLOCKED Chiwara / material supplier Yes — BBSC contributes only rock in current model; LCA is incomplete
OMPU reference document identity EXPERT-JUDGEMENT (pending) Chiwara / Adama No — model runs with PROVENANCE UNKNOWN, but not defensible for ISO 14071 review
Anti-termite reference area EXPERT-JUDGEMENT (pending) Chiwara / site engineer No — model runs with roof area proxy; divergence test XFAIL
Steel density for fenestration (columns N, O) EXPERT-JUDGEMENT (pending) Chiwara / structural engineer No — volume-basis only until attributed
Sand density 1600 kg/m³ scope EXPERT-JUDGEMENT (pending) Chiwara / Adama No — used only in row 72; question is whether it applies elsewhere
OMPU provenance for K29 water:earth ratio (0.2585) EXPERT-JUDGEMENT (pending) Chiwara No

§7 Divergence fixture location

backend/tests/fixtures/quantities_divergence.py

This file contains: - SPEC_PROJECT_TOTALS — the spec-faithful aggregate (Fixture 4 from the spec, as Excel computes it, bugs preserved). - CORRECTED_PROJECT_TOTALS — the corrected aggregate (after applying C1–C4; C5 deferred). - Five pytest functions (test_c1_* through test_c5_*) asserting the expected divergence.

These tests do not run the Python quantities module (which does not exist yet). They assert the expected relationship between spec and corrected values, so the implementation team knows exactly what to target. Once the module is implemented, the regression tests in backend/tests/regression/ will use the corrected values.