# Beam Analysis — where it stands Written 2026-09-05 against `a8222a3`. Numbers below are from that evening's comparer run; rerun the command rather than trusting them next week. Beam Analysis is two halves. **The host CPython half lives here and is built**: `beamcalc/` (the engine), `tools/ba_pagespec.py` (job ⇄ page), `tools/ba_web.py` + `tools/ba_web/static/` (the page). **The Revit half is not started**: the DesignHub button is still the `(WIP)` stub, and nothing yet writes the reads file `docs/ba-web-spec.md` §6 describes. The contract between the halves is that document; the job file is `beamcalc/1` JSON and `beamcalc/src/beamcalc/model.py:from_job` is its authority. ## Run it ```bash source .venv/bin/activate python -m pytest -q beamcalc/tests WillTools.extension/tests/test_ba_pagespec.py WillTools.extension/tests/test_ba_web.py python tools/ba_web.py --reads beamcalc/fixtures/rba5_16x22.json --open # the page cd beamcalc && PYTHONPATH=src python -m beamcalc fixtures/rba5_16x22.json -o /tmp/r.html # the engine alone ``` The page has been driven end to end over HTTP (spec → save → run → report) but **has not been opened in a browser on this machine** — the drawings in `ba_drawings.js` are syntax-checked only. The first WebView2 launch on the Revit side is their first real render; expect layout work there. ## The engine against the reference program Two of the owner's design packages (product codes RBA1, RBA5; the reference is Eriksson Beam v5.9.x) are transcribed as `beamcalc/fixtures/` and their printed tables extracted, station by station, into a gitignored truth set under `_scratch/eriksson_truth/`. The comparer: ```bash cd beamcalc && PYTHONPATH=src python tools/compare_eriksson.py fixtures/rba5_16x22.json ../_scratch/eriksson_truth/RBA5.json --full -o ../_scratch/eriksson_truth/RBA5_compare.md ``` Cells print **engine first, reference second**. The scoreboard at the top is the max deviation per quantity. **Agrees (RBA5, within 2 %):** Mu and φMn at every station; service stresses; reactions per case; deflections (≤ 2.6 %); bearing Vu; Vu at every station including the bearing centreline; As; Vs prov and φVn everywhere except the one station named below; the ramp of d through the end zone at 0.33 / 0.90 / 1.43 ft. **Open, in order of engineering weight:** 1. **Bearing φVn has no PCI Cr reduction** (`solve.py:_bearing`, flagged in its own note). Reference 58.5 / 54.8 k against our unreduced value. This is the only open item that changes a pass/fail answer. 2. **RBA1 As is +72 % over the whole beam** while Mu, φMn and c agree. RBA1 is Grade 80. `develop.ld_bar` now carries ACI 318-19's ψg (1.15 for Grade 80; owner 2026-09-06: "参考ACI吧"), which takes the As deviation from +72 % to +50 %. The residual ×1.5 has **no ACI text behind it** — the detailed 25.4.2.4(a) equation with real cb was tested and does not fit (`_scratch/eriksson_truth/ld_detailed_report.md`). Left as a recorded difference: this repo does not ship a fitted constant. 3. **Neutral axis c in the end zone** (RBA5 0.54 ft: 1.61 vs 1.38; 1.43 ft: 2.49 vs 2.67). The displaced-concrete trigger now uses c, which moved 1.43 ft from 2.42 to 2.49; the tension-side build-up of the top layer at 0.54 ft is unexplained. Pinned as a regression guard in `beamcalc/tests/test_shear_zones.py`, stated as not-agreeing. 4. **d just inside the bearing.** At the first station past the centreline the reference measures d from the hogging face (bw·d = 147.2 = 16 × 9.20) and we take the sagging one (204.8). Only that station; drives its Av req and f act too. 5. Vc is 3–10 % off at a handful of end-zone stations, downstream of 3. **Conventions learned the hard way, all now in code comments:** Vu at a bearing centreline is the overhang side (`_station_shear`); the reported d is the centre of tension *force* with strain-compatibility stress (`flexure.py`, the `wt` block); Vs prov is printed raw and the 22.5.1.2 cap is a flag; a symmetric stirrup zone counts once where it overlaps its mirror; `statics.shear_jump` is exact, not grid-neighbour. ## Where the mining stands The 28-document drop is inventoried in the private ledger. Extraction notes exist for every document but one long slab package, which is being mined in three page ranges, and one regression fixture (a second transfer beam) has failed to generate twice on the worker's side and is being retried. Notes are clues, not sources (`CLAUDE.md` § knowledge): nothing from them has been landed in a YAML layer yet, and the runbook's success metric says that is a debt, not progress.