Fix mutate_level_add: use generic C/O floor instead of room duplicate
Previously level_add copied the top storey exactly, duplicating all
named programme rooms and immediately triggering space-count failures
for every room on the new floor. The lex outer-search comparison
(-n_fails, score) then always rejected the multi-storey child because
its fail count was far higher than the single-storey parent.
Fix: retype all named-room leaves on the new storey to generic C or O
before admitting the child. The outer search then retypes them
incrementally via the normal retype operator. This allows level_add to
produce designs with the same fail count as the parent (storey_minimum
fail removed, no duplication fails added), making the multi-storey
transition visible to the lex selector.
Result on programme-house cold start (init.dom, 100k evals, 4 workers):
before: 6 fails, single-storey, stuck after 40k evals
after: 4 fails, two-storey, still improving at 100k
Also adds examples/harbor-house/ from urb/examples for future runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 10:33:05 +01:00
|
|
|
node:
|
|
|
|
|
- - 0.0
|
|
|
|
|
- 0.0
|
|
|
|
|
- - 25.0
|
|
|
|
|
- 2.0
|
|
|
|
|
- - 23.0
|
|
|
|
|
- 31.0
|
|
|
|
|
- - 0.0
|
|
|
|
|
- 31.0
|
|
|
|
|
perimeter:
|
|
|
|
|
a: private
|
|
|
|
|
b: private
|
|
|
|
|
c: null
|
|
|
|
|
d: null
|
|
|
|
|
rotation: 0
|
|
|
|
|
division:
|
|
|
|
|
- 0.5206890368316089
|
|
|
|
|
- 0.5206890368316089
|
|
|
|
|
height: 3.0
|
|
|
|
|
elevation: 0.0
|
|
|
|
|
wall_inner: 0.08
|
|
|
|
|
wall_outer: 0.25
|
|
|
|
|
l:
|
|
|
|
|
rotation: 1
|
|
|
|
|
division:
|
|
|
|
|
- 0.4900271770215713
|
|
|
|
|
- 0.4900271770215713
|
|
|
|
|
l:
|
|
|
|
|
rotation: 2
|
|
|
|
|
division:
|
|
|
|
|
- 0.28955830710300473
|
|
|
|
|
- 0.28955830710300473
|
|
|
|
|
l:
|
|
|
|
|
rotation: 1
|
|
|
|
|
division:
|
|
|
|
|
- 0.5900577549923657
|
|
|
|
|
- 0.5900577549923657
|
|
|
|
|
l:
|
|
|
|
|
rotation: 0
|
|
|
|
|
division:
|
|
|
|
|
- 0.5042565018475718
|
|
|
|
|
- 0.5042565018475718
|
|
|
|
|
l:
|
§39.4: tighten generic-type matching, reverting the harbor rename
Supersedes the previous commit's approach. Renaming harbor's four colliding
codes fixed one programme; tightening the matching rule fixes the rule, so a
room may be called anything. cr1/of/st1/st2 are restored and the examples are
byte-identical to their pre-§39 state -- which also means existing .dom
artefacts (evolved-3M*) stay valid, so migrate_ju3_rename.py is deleted.
The rule: Urb has exactly three GENERIC structural types (get_space_types:
qw/C O S/), the leaves the search creates. Measured across the corpus: 154 C,
110 O, 1 S, not one lowercase generic -- while every programme code is
lowercase, including single-character ones (r, t, m, n). Case is the
discriminator, not length. Every generic test was type[0].lower() in (...), a
case-insensitive PREFIX that swept up any programme code starting with those
letters; they now match the generic set exactly. 30 sites across dom, fitness,
graph, operators, programme, shapecurve and bubble.
NOT applied to the SEMANTIC prefixes: l/k/b/t classify programme codes by first
letter (graph.py builds bedroom<->toilet and kitchen<->living relations from
them) and stay prefix-based. Where the namespaces were mixed in one expression
they were split -- has_circulation's ("b","l","k","c") is three semantic
prefixes plus dom.is_circulation; access()'s ("l","c","s") is semantic l plus
the generic circulation set.
New: dom.GENERIC_{CIRCULATION,OUTSIDE,TYPES} + is_generic(); fitness.
_generic_class(), replacing the _t0 dispatch in quality_size/quality_width/
quality_proportion/value_rate -- the four terms that mattered most and that a
first sweep missed, since they dispatch through a t0 variable rather than an
inline test. graph._adjacency_target resolves a generic adjacency requirement
(programmes write "adjacency: [c, o]") to the generic set while every other
requirement keeps Perl's prefix semantics.
Two subtleties: S is in both generic sets but takes the OUTSIDE parameter
families -- a first translation tested circulation first and silently gave S
the circulation params, caught by test_get_space_params_sahn_proportion. And
validate_codes survives, narrowed to a code spelled exactly C/O/S, which is a
genuine ambiguity; merely starting with c/o/s is now fine.
Invariant asserted as a test: test_scoring_is_invariant_under_programme_code_
spelling relabels one tree and its config together and re-scores. Bit-identical
across 12 comparisons (6 seeds x collapse on/off).
Re-baseline (seed 1, 20k, original names): 58 fails (15 hard / 43 soft) against
the real 37-instance programme, with cr1 at 79.1 m2 vs declared 80 (was 32.9
and 17.1), of/st1/st2 all present and in band, and one fail naming any of them.
57 -> 58 on a 5-instance-harder programme is within noise: "did not regress".
Fallout (§39.5): 2g7.5's CP-SAT seeder win does not survive. Over 6 seeds --
harbor real 102/114 (cpsat loses), harbor old-effective 98/99 (tie, so the win
was already marginal), maple-court 156/144 (cpsat wins). maple is the control:
the solver did not regress, harbor's programme changed. Test xfail'd with that
reason plus a maple companion; both assign_solver flags stay default off.
Filed homemaker-py-w6x to re-check other narrow-margin harbor A/Bs.
345 passed, 1 xfailed, same 7 pre-existing fixture failures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 09:45:28 +00:00
|
|
|
type: st2
|
Fix mutate_level_add: use generic C/O floor instead of room duplicate
Previously level_add copied the top storey exactly, duplicating all
named programme rooms and immediately triggering space-count failures
for every room on the new floor. The lex outer-search comparison
(-n_fails, score) then always rejected the multi-storey child because
its fail count was far higher than the single-storey parent.
Fix: retype all named-room leaves on the new storey to generic C or O
before admitting the child. The outer search then retypes them
incrementally via the normal retype operator. This allows level_add to
produce designs with the same fail count as the parent (storey_minimum
fail removed, no duplication fails added), making the multi-storey
transition visible to the lex selector.
Result on programme-house cold start (init.dom, 100k evals, 4 workers):
before: 6 fails, single-storey, stuck after 40k evals
after: 4 fails, two-storey, still improving at 100k
Also adds examples/harbor-house/ from urb/examples for future runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 10:33:05 +01:00
|
|
|
rotation: 0
|
|
|
|
|
r:
|
§39.4: tighten generic-type matching, reverting the harbor rename
Supersedes the previous commit's approach. Renaming harbor's four colliding
codes fixed one programme; tightening the matching rule fixes the rule, so a
room may be called anything. cr1/of/st1/st2 are restored and the examples are
byte-identical to their pre-§39 state -- which also means existing .dom
artefacts (evolved-3M*) stay valid, so migrate_ju3_rename.py is deleted.
The rule: Urb has exactly three GENERIC structural types (get_space_types:
qw/C O S/), the leaves the search creates. Measured across the corpus: 154 C,
110 O, 1 S, not one lowercase generic -- while every programme code is
lowercase, including single-character ones (r, t, m, n). Case is the
discriminator, not length. Every generic test was type[0].lower() in (...), a
case-insensitive PREFIX that swept up any programme code starting with those
letters; they now match the generic set exactly. 30 sites across dom, fitness,
graph, operators, programme, shapecurve and bubble.
NOT applied to the SEMANTIC prefixes: l/k/b/t classify programme codes by first
letter (graph.py builds bedroom<->toilet and kitchen<->living relations from
them) and stay prefix-based. Where the namespaces were mixed in one expression
they were split -- has_circulation's ("b","l","k","c") is three semantic
prefixes plus dom.is_circulation; access()'s ("l","c","s") is semantic l plus
the generic circulation set.
New: dom.GENERIC_{CIRCULATION,OUTSIDE,TYPES} + is_generic(); fitness.
_generic_class(), replacing the _t0 dispatch in quality_size/quality_width/
quality_proportion/value_rate -- the four terms that mattered most and that a
first sweep missed, since they dispatch through a t0 variable rather than an
inline test. graph._adjacency_target resolves a generic adjacency requirement
(programmes write "adjacency: [c, o]") to the generic set while every other
requirement keeps Perl's prefix semantics.
Two subtleties: S is in both generic sets but takes the OUTSIDE parameter
families -- a first translation tested circulation first and silently gave S
the circulation params, caught by test_get_space_params_sahn_proportion. And
validate_codes survives, narrowed to a code spelled exactly C/O/S, which is a
genuine ambiguity; merely starting with c/o/s is now fine.
Invariant asserted as a test: test_scoring_is_invariant_under_programme_code_
spelling relabels one tree and its config together and re-scores. Bit-identical
across 12 comparisons (6 seeds x collapse on/off).
Re-baseline (seed 1, 20k, original names): 58 fails (15 hard / 43 soft) against
the real 37-instance programme, with cr1 at 79.1 m2 vs declared 80 (was 32.9
and 17.1), of/st1/st2 all present and in band, and one fail naming any of them.
57 -> 58 on a 5-instance-harder programme is within noise: "did not regress".
Fallout (§39.5): 2g7.5's CP-SAT seeder win does not survive. Over 6 seeds --
harbor real 102/114 (cpsat loses), harbor old-effective 98/99 (tie, so the win
was already marginal), maple-court 156/144 (cpsat wins). maple is the control:
the solver did not regress, harbor's programme changed. Test xfail'd with that
reason plus a maple companion; both assign_solver flags stay default off.
Filed homemaker-py-w6x to re-check other narrow-margin harbor A/Bs.
345 passed, 1 xfailed, same 7 pre-existing fixture failures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 09:45:28 +00:00
|
|
|
type: st1
|
Fix mutate_level_add: use generic C/O floor instead of room duplicate
Previously level_add copied the top storey exactly, duplicating all
named programme rooms and immediately triggering space-count failures
for every room on the new floor. The lex outer-search comparison
(-n_fails, score) then always rejected the multi-storey child because
its fail count was far higher than the single-storey parent.
Fix: retype all named-room leaves on the new storey to generic C or O
before admitting the child. The outer search then retypes them
incrementally via the normal retype operator. This allows level_add to
produce designs with the same fail count as the parent (storey_minimum
fail removed, no duplication fails added), making the multi-storey
transition visible to the lex selector.
Result on programme-house cold start (init.dom, 100k evals, 4 workers):
before: 6 fails, single-storey, stuck after 40k evals
after: 4 fails, two-storey, still improving at 100k
Also adds examples/harbor-house/ from urb/examples for future runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 10:33:05 +01:00
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
rotation: 1
|
|
|
|
|
division:
|
|
|
|
|
- 0.5042565018475718
|
|
|
|
|
- 0.5042565018475718
|
|
|
|
|
l:
|
|
|
|
|
type: O
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
type: ut1
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
rotation: 2
|
|
|
|
|
division:
|
|
|
|
|
- 0.5254855092815014
|
|
|
|
|
- 0.5254855092815014
|
|
|
|
|
l:
|
|
|
|
|
rotation: 1
|
|
|
|
|
division:
|
|
|
|
|
- 0.7453088885860744
|
|
|
|
|
- 0.7453088885860744
|
|
|
|
|
l:
|
|
|
|
|
rotation: 2
|
|
|
|
|
division:
|
|
|
|
|
- 0.5622884610865619
|
|
|
|
|
- 0.5622884610865619
|
|
|
|
|
l:
|
|
|
|
|
type: k1
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
rotation: 3
|
|
|
|
|
division:
|
|
|
|
|
- 0.545507016217933
|
|
|
|
|
- 0.545507016217933
|
|
|
|
|
l:
|
|
|
|
|
type: ws1
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
§39.4: tighten generic-type matching, reverting the harbor rename
Supersedes the previous commit's approach. Renaming harbor's four colliding
codes fixed one programme; tightening the matching rule fixes the rule, so a
room may be called anything. cr1/of/st1/st2 are restored and the examples are
byte-identical to their pre-§39 state -- which also means existing .dom
artefacts (evolved-3M*) stay valid, so migrate_ju3_rename.py is deleted.
The rule: Urb has exactly three GENERIC structural types (get_space_types:
qw/C O S/), the leaves the search creates. Measured across the corpus: 154 C,
110 O, 1 S, not one lowercase generic -- while every programme code is
lowercase, including single-character ones (r, t, m, n). Case is the
discriminator, not length. Every generic test was type[0].lower() in (...), a
case-insensitive PREFIX that swept up any programme code starting with those
letters; they now match the generic set exactly. 30 sites across dom, fitness,
graph, operators, programme, shapecurve and bubble.
NOT applied to the SEMANTIC prefixes: l/k/b/t classify programme codes by first
letter (graph.py builds bedroom<->toilet and kitchen<->living relations from
them) and stay prefix-based. Where the namespaces were mixed in one expression
they were split -- has_circulation's ("b","l","k","c") is three semantic
prefixes plus dom.is_circulation; access()'s ("l","c","s") is semantic l plus
the generic circulation set.
New: dom.GENERIC_{CIRCULATION,OUTSIDE,TYPES} + is_generic(); fitness.
_generic_class(), replacing the _t0 dispatch in quality_size/quality_width/
quality_proportion/value_rate -- the four terms that mattered most and that a
first sweep missed, since they dispatch through a t0 variable rather than an
inline test. graph._adjacency_target resolves a generic adjacency requirement
(programmes write "adjacency: [c, o]") to the generic set while every other
requirement keeps Perl's prefix semantics.
Two subtleties: S is in both generic sets but takes the OUTSIDE parameter
families -- a first translation tested circulation first and silently gave S
the circulation params, caught by test_get_space_params_sahn_proportion. And
validate_codes survives, narrowed to a code spelled exactly C/O/S, which is a
genuine ambiguity; merely starting with c/o/s is now fine.
Invariant asserted as a test: test_scoring_is_invariant_under_programme_code_
spelling relabels one tree and its config together and re-scores. Bit-identical
across 12 comparisons (6 seeds x collapse on/off).
Re-baseline (seed 1, 20k, original names): 58 fails (15 hard / 43 soft) against
the real 37-instance programme, with cr1 at 79.1 m2 vs declared 80 (was 32.9
and 17.1), of/st1/st2 all present and in band, and one fail naming any of them.
57 -> 58 on a 5-instance-harder programme is within noise: "did not regress".
Fallout (§39.5): 2g7.5's CP-SAT seeder win does not survive. Over 6 seeds --
harbor real 102/114 (cpsat loses), harbor old-effective 98/99 (tie, so the win
was already marginal), maple-court 156/144 (cpsat wins). maple is the control:
the solver did not regress, harbor's programme changed. Test xfail'd with that
reason plus a maple companion; both assign_solver flags stay default off.
Filed homemaker-py-w6x to re-check other narrow-margin harbor A/Bs.
345 passed, 1 xfailed, same 7 pre-existing fixture failures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 09:45:28 +00:00
|
|
|
type: cr1
|
Fix mutate_level_add: use generic C/O floor instead of room duplicate
Previously level_add copied the top storey exactly, duplicating all
named programme rooms and immediately triggering space-count failures
for every room on the new floor. The lex outer-search comparison
(-n_fails, score) then always rejected the multi-storey child because
its fail count was far higher than the single-storey parent.
Fix: retype all named-room leaves on the new storey to generic C or O
before admitting the child. The outer search then retypes them
incrementally via the normal retype operator. This allows level_add to
produce designs with the same fail count as the parent (storey_minimum
fail removed, no duplication fails added), making the multi-storey
transition visible to the lex selector.
Result on programme-house cold start (init.dom, 100k evals, 4 workers):
before: 6 fails, single-storey, stuck after 40k evals
after: 4 fails, two-storey, still improving at 100k
Also adds examples/harbor-house/ from urb/examples for future runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 10:33:05 +01:00
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
type: O
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
type: da1
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
rotation: 2
|
|
|
|
|
division:
|
|
|
|
|
- 0.5017908930114854
|
|
|
|
|
- 0.5017908930114854
|
|
|
|
|
l:
|
|
|
|
|
type: r
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
type: li1
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
rotation: 0
|
|
|
|
|
division:
|
|
|
|
|
- 0.4006976137653344
|
|
|
|
|
- 0.4006976137653344
|
|
|
|
|
l:
|
|
|
|
|
rotation: 3
|
|
|
|
|
division:
|
|
|
|
|
- 0.48703066466032097
|
|
|
|
|
- 0.48703066466032097
|
|
|
|
|
l:
|
|
|
|
|
rotation: 2
|
|
|
|
|
division:
|
|
|
|
|
- 0.5562346554544078
|
|
|
|
|
- 0.5562346554544078
|
|
|
|
|
l:
|
|
|
|
|
type: m
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
rotation: 2
|
|
|
|
|
division:
|
|
|
|
|
- 0.5042565018475718
|
|
|
|
|
- 0.5042565018475718
|
|
|
|
|
l:
|
|
|
|
|
type: me1
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
type: C
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
rotation: 2
|
|
|
|
|
division:
|
|
|
|
|
- 0.6464404401824229
|
|
|
|
|
- 0.6464404401824229
|
|
|
|
|
l:
|
|
|
|
|
type: O
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
type: t
|
|
|
|
|
rotation: 0
|
|
|
|
|
r:
|
|
|
|
|
type: r
|
|
|
|
|
rotation: 3
|