homemaker-layout/tests
Claude a76ed3b9b8
Quality aggregation: divide out how many questions a leaf was asked
39.17 left the search's storey choice unexplained and blamed value_rate. It is
not the rate, or not only.

Measured over the twelve baseline runs, value/cost by leaf kind: outside ground
7.40, roof terrace 2.69, room 0.34, circulation 0.02. A terrace returns 2.7x
its cost where a room returns a third of it, so filling upper storeys with
terrace is not the search leaving value on the table -- it is by a wide margin
the most profitable thing the objective offers. 7% of the corpus area produces
32% of its value.

Most of that gap is mean quality: 0.986 for a terrace against 0.223 for a
room. Quality is a PRODUCT of factors and the kinds are not asked the same
number of questions -- an outside leaf is exempt from size, crinkliness and
access, so 3 of 7 factors can ever bite it against a room's 6. Each exemption
is individually right (no programme size target; uncovered outside is lit by
definition; ground-level outside needs no access). The consequence is not: a
leaf exempt from the two harshest factors out-scores one judged on them and
doing well, purely by not being asked, and quality multiplies the value rate.

Stated generally, and this is not about outside space: under a product, adding
any new quality criterion mechanically devalues every leaf it applies to,
including leaves that score 1.0 on it. The objective's scale should not depend
on how many things it measures.

quality_aggregate="geometric_mean" (default OFF, "product" is stock) divides
that out. Computed in log space so six small factors cannot underflow the
product before the root is taken; a zero factor still gives zero, so a fully
buried leaf is worth nothing either way.

Telling "exempt" from "asked and scored 1.0" needs factor_is_asked, which
restates conditions that live inside the quality_* methods. That duplication
can drift, so tests/test_fitness_aggregate.py pins it against every leaf in the
corpus: wherever the predicate says exempt, the factor really is 1.0.

Fail set byte-identical everywhere, and for a stronger reason than 39.13/39.14
had: evaluate_leaf emits each fail from the factor itself before anything is
combined, so no aggregation can move one. Score effect +37% to +169%, reaching
all four programmes where the crinkliness changes reached two; room value/cost
0.34 -> 0.66, circulation 0.02 -> 0.07.

Deliberately not fixed: a terrace still out-earns a room 4:1, which is the
rates (value_supported = value_inside = 300 against costs of 110 and 200), not
the aggregation. That is a design judgement for the programme author, and
39.16 is a standing reminder that "this inherited constant looks wrong" has
been wrong twice already in this section. Left open on ecx with the numbers.

A/B running; verdict to follow.

Refs homemaker-py-ecx.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-09-05 18:57:00 +00:00
..
_helpers.py §39.7: access requirements become a declared usage: attribute (homemaker-py-sel) 2026-08-26 13:39:41 +00:00
test_collapse_global.py §39.7: access requirements become a declared usage: attribute (homemaker-py-sel) 2026-08-26 13:39:41 +00:00
test_collapse_insearch.py Replace the stale 15-fail acceptance target with the cold-start baseline 2026-09-04 17:16:10 +00:00
test_compose.py §39.4: tighten generic-type matching, reverting the harbor rename 2026-08-26 09:45:28 +00:00
test_conn_grade.py qi6: graded circulation-connectivity signal (§18) 2026-07-18 18:44:24 +01:00
test_cpsat.py homemaker-py-2g7.5: CP-SAT exact room-code assignment (seeder + reassign op) 2026-08-04 09:19:36 +01:00
test_dom_corpus.py §39.7: access requirements become a declared usage: attribute (homemaker-py-sel) 2026-08-26 13:39:41 +00:00
test_driver.py n_workers is an algorithm parameter, not noise 2026-08-29 12:52:33 +00:00
test_evolve_cli.py x3b/§13.10: productionise leaf-sharing — per-code share grain + CLI wiring 2026-06-28 22:04:35 +01:00
test_evolve_preflight.py Pre-flight: check the ground floor's frontage, not the per-storey average 2026-09-05 17:46:52 +00:00
test_fitness.py Make both failing tests assert their intent, not stale artefacts 2026-08-29 07:11:25 +00:00
test_fitness_aggregate.py Quality aggregation: divide out how many questions a leaf was asked 2026-09-05 18:57:00 +00:00
test_fitness_crinkliness.py Make the crinkliness factor one-sided: stop billing the daylit wall twice 2026-09-05 07:27:02 +00:00
test_genome.py Phase 6 §11.5: structural niching + restarts — negative result (c4c.5) 2026-06-18 23:42:39 +01:00
test_geometry.py Rename package: homemaker → homemaker-layout 2026-06-14 08:18:06 +01:00
test_graph.py Missing-space cascade no longer weighted by YAML verbosity 2026-08-29 09:33:40 +00:00
test_innerloop.py Swap inner loop default from CMA-ES to Nelder-Mead (homemaker-py-d6d) 2026-06-14 08:51:22 +01:00
test_multi_use.py §39.7: access requirements become a declared usage: attribute (homemaker-py-sel) 2026-08-26 13:39:41 +00:00
test_operators.py Recover most of the cpsat test-suite cost; keep the part that is real 2026-08-29 18:55:54 +00:00
test_oracle.py Rename package: homemaker → homemaker-layout 2026-06-14 08:18:06 +01:00
test_programme.py §39.7: access requirements become a declared usage: attribute (homemaker-py-sel) 2026-08-26 13:39:41 +00:00
test_shapecurve.py Shape-curve DP models leaf-sharing, so it can fire on real runs 2026-08-29 21:36:45 +00:00
test_staging.py §39.4: tighten generic-type matching, reverting the harbor rename 2026-08-26 09:45:28 +00:00
test_superposition.py §39.7: access requirements become a declared usage: attribute (homemaker-py-sel) 2026-08-26 13:39:41 +00:00