Remove ratio_circulation: the score is already a ratio

Owner: "I think a corridor could be worth a sixth of a room, this is ok. maybe
we should dump the ratio_circulation altogether if there is already a pressure
in circulation caused by the cost benefit ratio per msq. this is the kind of
thing we want to root out of the scoring model: anything that is double
counting, or using a gaussian where a linear ramp is appropriate, etc."

value_circulation = 50 stands; hxi's rate question is closed.

The duplication argument is stronger than it first looks. score = value/cost is
already a ratio, so the per-m2 economics (50 against a build cost of 200) is not
merely an absolute pressure -- adding corridor moves value/cost by an amount
that depends on how much of the building is already corridor. It is ALREADY
proportional. ratio_circulation said the same thing again as a whole-building
multiplier, on a curve where twice the corridor is far more than twice as bad.

Correction to my own first measurement: I overrode ratio_circulation and got
scores going DOWN when a <=1 multiplier was removed, which is impossible. All
four corpus programmes DECLARE ratio_circulation, so the CONF_DEFAULTS value I
had changed was never in play and the two arms differed only in sigma. Same
trap as value_supported in 39.19.

Against the keep-it case, recorded because it is the one real argument: three of
four declare a POSITIVE target (harbor/maple 0.08, health-centre 0.10), making
the term formally two-sided rather than "less is better". It does not survive
the numbers -- the lower side is worth at most 13.3% on the large programmes
against 99% on the upper side, and "a building needs some circulation" is
enforced structurally by access and connectivity, which no amount of value can
buy off.

Disabled in CONF_DEFAULTS and the four corpus configs, each with the reason
inline and a note that a [target, sigma] pair re-enables it. Fail sets
unchanged; it was always a value multiplier. Scores +42% to +7712%.

39.24 also sweeps every remaining term against the owner's two tests. Verdicts:
perpendicular, proportion, width, crinkliness, access, size's lower side,
ratio_outside, staircase volume and the count/limit fails are all sound.
Filed as homemaker-py-dpt: size's UPPER side (cost already charges area; 82% of
size fails are over-target), the minimum-internal-area factor (a third
statement of "build the rooms"), the 0.5**n_fails curve (a ruling, not a
measurement), and two dead paths -- ratio_public/private_outside, which no
config declares, and the daylight factor pinned to 1.0 since the descope.

Also updated a test I added last turn which asserted ratio_circulation was the
second charge; it now pins that the linear ramp is the ONLY one.

419 passed.

Closes homemaker-py-hxi.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
This commit is contained in:
Claude 2026-09-06 15:28:33 +00:00
parent f07b3865ef
commit a7ef9e2fa0
No known key found for this signature in database
7 changed files with 144 additions and 16 deletions

View file

@ -7971,3 +7971,83 @@ untouched and unruled: `value_circulation` = 50 against `value_inside` = 300, a
room per square metre is a design judgement, not something measurement settles,
and the linear ramp the owner describes is only as steep as that number makes
it. Left open on the bead.
### 39.24 `ratio_circulation` removed, and a sweep for the rest of its kind (`homemaker-py-hxi`)
Owner, closing the rate question and opening a general one:
> I think a corridor could be worth a sixth of a room, this is ok. maybe we
> should dump the ratio_circulation altogether if there is already a pressure in
> circulation caused by the cost benefit ratio per msq. this is the kind of
> thing we want to root out of the scoring model: anything that is double
> counting, or using a gaussian where a linear ramp is appropriate, etc.
So `value_circulation = 50` stands, and `hxi`'s rate question is closed.
**`ratio_circulation` is a duplicate, and the argument is stronger than it first
looks.** The score is `value / cost` — already a ratio. So the per-m² economics
(50 against a build cost of 200) is not merely an *absolute* pressure against
corridor area: adding corridor moves `value/cost` by an amount that depends on
how much of the building is already corridor. It is **already proportional**.
`ratio_circulation` states the same thing a second time, as a whole-building
multiplier, on a curve where twice the corridor is far more than twice as bad.
**A correction to my own first measurement.** I initially measured this by
overriding `ratio_circulation` and comparing — and got scores going *down* when
a ≤1 multiplier was removed, which is impossible. The cause: all four corpus
programmes **declare** `ratio_circulation` themselves, so the `CONF_DEFAULTS`
value I had changed was never in play, and my "with" arm was accidentally
comparing two different sigmas. The same trap as `value_supported` in §39.19.
Measured properly, disabling it raises every score, by +42% to +7712%
(programme-house s2, which is 44% circulation).
**And the declared values are not what the default suggests:**
| programme | declared | worst the *lower* side can cost |
|---|---|---|
| harbor-house | [0.08, 0.15] | 13.3% |
| maple-court | [0.08, 0.15] | 13.3% |
| health-centre | [0.10, 0.12] | 29.3% |
| programme-house | [0.00, 0.15] | 0% |
| `CONF_DEFAULTS` | [0.00, 0.20] | 0% |
Three of the four target a *positive* circulation fraction, so the term is
formally two-sided, not "less is better" — and a two-sided target is exactly
what a gaussian is for. That is the one argument for keeping it. It does not
survive the numbers: the lower side ("a building needs some circulation") is
worth at most 13% on the two large programmes, while the upper side reaches
99%, and the lower side's job is done structurally anyway by the access and
connectivity checks, which no amount of value can buy off. What is left is an
upper-side penalty, and the upper side is the duplicated one.
**Shipped:** `ratio_circulation` disabled — `None` in `CONF_DEFAULTS` and in the
four corpus `patterns.config` files, each with the reason inline and a note that
a `[target, sigma]` pair re-enables it. Fail sets are unchanged; it was always a
value multiplier, never a fail source.
**The sweep.** Every term in the objective, against the two tests the owner
named — does it double-count, and is a gaussian the right curve for what it
measures?
| term | measures | shape | verdict |
|---|---|---|---|
| perpendicular | corner angle vs 90° | two-sided gaussian | **OK** — a right angle is a genuine optimum |
| proportion | aspect vs target | clipped, one free side | **OK** |
| width | narrowest vs minimum | clipped, one free side | **OK** |
| crinkliness | daylight per unit floor | one-sided since §39.14 | **OK** |
| access | has a circulation neighbour | binary | **OK** — not a curve |
| size, *lower* side | area vs programme target | gaussian | **OK** — a room has a right size |
| size, *upper* side | area over target | gaussian | **SUSPECT**`cost` already charges floor area, and an oversize room is wasteful in proportion, not quadratically. §39.15 found 82% of size fails are over-target. Not changed: §39.15 also found this upper half is the main brake on growth, so removing it needs the value rates looked at first. |
| ratio_outside | outdoor fraction vs target | two-sided gaussian | **OK** — and its binding side counters the economics rather than duplicating it, since outdoor space is profitable |
| ratio_circulation | circulation fraction | gaussian, effectively one-sided | **REMOVED** |
| min internal area | total room area below 1.2× the programme | one-sided gaussian | **SUSPECT** — "build the rooms you were asked for" is already said by the missing-space fails and again by `quality_size`. A third statement of it. |
| staircase volume | stair fit | gaussian | **OK** — a stair has a right size |
| stair count, storey limits | counts vs bounds | binary fails | **OK** |
| `ratio_public_outside`, `ratio_private_outside` | boundary-length ratios | gaussian | **DEAD** — absent from `CONF_DEFAULTS` and from every corpus config, so the branch never runs |
| `daylight` factor | pinned to 1.0 | constant | **DEAD**`URB_NO_OCCLUSION` (§6); it is a factor that can never be anything but 1 |
| `0.5 ** n_fails` | fail count | exponential | **RULING WANTED** — each failure independently halves the building. Coherent as a product of independent defects, but it is not "twice as many failures is twice as bad", and it is the single largest term in the objective. |
The three SUSPECT entries and the fail multiplier are filed rather than changed
— each needs a ruling or a rate change behind it, and §39.16 is the standing
reminder about acting on an inherited constant before understanding what it
measures. The two DEAD entries are inert and cost nothing but confusion.

View file

@ -267,9 +267,14 @@ storey_limit: 3
force_roof_garden: 0
# Circulation ratio (allow more circulation for larger building)
# homemaker-py-hxi (DESIGN.md §39.24): disabled. The score is value/cost, a
# ratio, so the per-m2 economics (circulation worth 50 against a build cost of
# 200) is ALREADY a proportional pressure against circulation -- this said the
# same thing a second time, and with a curve where twice the corridor is far
# more than twice as bad. Its other side, "a building needs some circulation",
# was worth at most 13% here and is enforced structurally anyway by the access
# and connectivity checks. Set a [target, sigma] pair to re-enable.
ratio_circulation:
- 0.08
- 0.15
# Outside space ratio (courtyard requirement)
ratio_outside:

View file

@ -351,9 +351,14 @@ storey_minimum: 1
storey_limit: 2
force_roof_garden: 0
# homemaker-py-hxi (DESIGN.md §39.24): disabled. The score is value/cost, a
# ratio, so the per-m2 economics (circulation worth 50 against a build cost of
# 200) is ALREADY a proportional pressure against circulation -- this said the
# same thing a second time, and with a curve where twice the corridor is far
# more than twice as bad. Its other side, "a building needs some circulation",
# was worth at most 13% here and is enforced structurally anyway by the access
# and connectivity checks. Set a [target, sigma] pair to re-enable.
ratio_circulation:
- 0.10
- 0.12
ratio_outside:
- 0.06

View file

@ -406,9 +406,14 @@ storey_limit: 4
force_roof_garden: 0
# Circulation ratio (allow more circulation for larger building)
# homemaker-py-hxi (DESIGN.md §39.24): disabled. The score is value/cost, a
# ratio, so the per-m2 economics (circulation worth 50 against a build cost of
# 200) is ALREADY a proportional pressure against circulation -- this said the
# same thing a second time, and with a curve where twice the corridor is far
# more than twice as bad. Its other side, "a building needs some circulation",
# was worth at most 13% here and is enforced structurally anyway by the access
# and connectivity checks. Set a [target, sigma] pair to re-enable.
ratio_circulation:
- 0.08
- 0.15
# Outside space ratio (courtyard requirement)
ratio_outside:

View file

@ -82,9 +82,14 @@ storey_limit: 5
force_roof_garden: 0
# Circulation ratio (penalise excessive corridors)
# homemaker-py-hxi (DESIGN.md §39.24): disabled. The score is value/cost, a
# ratio, so the per-m2 economics (circulation worth 50 against a build cost of
# 200) is ALREADY a proportional pressure against circulation -- this said the
# same thing a second time, and with a curve where twice the corridor is far
# more than twice as bad. Its other side, "a building needs some circulation",
# was worth at most 13% here and is enforced structurally anyway by the access
# and connectivity checks. Set a [target, sigma] pair to re-enable.
ratio_circulation:
- 0.00
- 0.15
# Outside space ratio
ratio_outside:

View file

@ -210,7 +210,25 @@ CONF_DEFAULTS: dict = {
"door_width": 1.2,
"plot_ratio": [2.00, 0.50],
"ratio_outside": [0.33, 0.15],
"ratio_circulation": [0.00, 0.20],
# homemaker-py-hxi (DESIGN.md §39.24). Was [0.00, 0.20] -- a gaussian on
# the circulation FRACTION, targeting zero, applied as a multiplier to the
# whole building's value (0.013..0.70 across the corpus). `None` disables
# it, because it double-counts and does so with the wrong curve.
#
# The score is `value / cost`, which is already a ratio, so the per-m2
# economics -- circulation worth 50 against a build cost of 200 -- is
# already a PROPORTIONAL pressure and not merely an absolute one: adding
# corridor moves value/cost by an amount that depends on how much of the
# building is already corridor. A second, super-linear term on the same
# quantity says the same thing twice, and says it with a curve where twice
# the corridor is far more than twice as bad (0.10 -> x0.882, 0.20 ->
# x0.607, 0.40 -> x0.135).
#
# Contrast `ratio_outside`, which is KEPT: its target is 0.33, not zero, so
# it is a genuine two-sided requirement rather than "less is better", and
# its binding side (do not build too much outdoor space) is not something
# the economics expresses -- outdoor space is profitable.
"ratio_circulation": None,
# PROVENANCE (DESIGN.md §39.16). This is Christopher Alexander, A Pattern
# Language 159, "Light on Two Sides of Every Room" -- not an arbitrary
# constant. The factor is evaluated at `1/crink = A/(L*h)`: floor area per
@ -2048,6 +2066,7 @@ class Fitness:
factor *= self.ratio_o(ratios)
circ_ratio = self.conf("ratio_circulation")
if circ_ratio is not None: # §39.24: off by default
factor *= self.ratio_type(ratios, "c", circ_ratio[0], circ_ratio[1])
min_required = 0.0

View file

@ -150,13 +150,22 @@ def test_twice_the_corridor_is_exactly_twice_as_bad():
"so, §39.23's justification needs revisiting")
def test_the_amount_of_circulation_is_still_priced():
"""Removing the per-leaf cap must not make corridors free. Two charges
remain, and they are the ones that do not depend on how it is cut up."""
def test_the_amount_of_circulation_is_priced_exactly_once():
"""Removing the per-leaf cap must not make corridors free -- but the charge
that remains must also be the ONLY one (§39.24).
The linear ramp is `value_circulation` against the build cost: every square
metre of corridor is worth less than it costs, and because the score is
`value / cost` that pressure is already proportional to how much of the
building is corridor. `ratio_circulation` said the same thing a second time
and is disabled; if it comes back, either it has a justification this test
does not know about or the double count has returned.
"""
fit = _fit()
assert fit.conf("value_circulation") < fit.cost("inside"), (
"a corridor must cost more to build than it is worth, or there is no "
"linear ramp pushing the search to use less of it")
assert fit.conf("ratio_circulation") is not None, (
"the building-level circulation fraction check is the other charge"
)
assert fit.conf("ratio_circulation") is None, (
"ratio_circulation duplicates the per-m2 economics (§39.24)")
assert fit.conf("size_circulation") is None, "§39.23"
assert fit.conf("proportion_circulation") is None, "§39.22"