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
|
|
|
---
|
|
|
|
|
# Harbor House - Programme-driven building evolution (Simplified)
|
|
|
|
|
# Two-story community living facility for 50+ residents
|
|
|
|
|
# Using anonymous interchangeable rooms to reduce complexity
|
|
|
|
|
|
|
|
|
|
# Building programme: community living spaces
|
|
|
|
|
spaces:
|
|
|
|
|
# GROUND FLOOR - Main Community Areas
|
§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
|
|
|
cr1:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: living
|
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
|
|
|
name: Common Room with Fireplace
|
|
|
|
|
size:
|
|
|
|
|
- 80.0
|
|
|
|
|
- 10.0
|
|
|
|
|
width:
|
|
|
|
|
- 6.0
|
|
|
|
|
- 1.5
|
|
|
|
|
proportion:
|
|
|
|
|
- 2.0
|
|
|
|
|
- 0.5
|
|
|
|
|
level: 0
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
- o
|
|
|
|
|
|
|
|
|
|
ef1:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: none
|
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
|
|
|
name: Entrance Foyer
|
|
|
|
|
size:
|
|
|
|
|
- 15.0
|
|
|
|
|
- 3.0
|
|
|
|
|
width:
|
|
|
|
|
- 3.0
|
|
|
|
|
- 0.5
|
|
|
|
|
level: 0
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
2026-07-31 00:16:12 +01:00
|
|
|
# homemaker-py-1s3 (§26 path b): a foyer can double as an informal meeting
|
|
|
|
|
# nook (Stewart Brand "loose-fit") — declared here, validated against
|
|
|
|
|
# interchangeable()'s S1-S4 bounds before it's ever honoured.
|
|
|
|
|
co_locate:
|
|
|
|
|
- m
|
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
|
|
|
|
|
|
|
|
da1:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: living
|
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
|
|
|
name: Dining Area
|
|
|
|
|
size:
|
|
|
|
|
- 60.0
|
|
|
|
|
- 8.0
|
|
|
|
|
width:
|
|
|
|
|
- 5.0
|
|
|
|
|
- 1.0
|
|
|
|
|
proportion:
|
|
|
|
|
- 2.5
|
|
|
|
|
- 0.8
|
|
|
|
|
level: 0
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
- k1
|
|
|
|
|
- o
|
|
|
|
|
|
|
|
|
|
k1:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: kitchen
|
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
|
|
|
name: Kitchen
|
|
|
|
|
size:
|
|
|
|
|
- 30.0
|
|
|
|
|
- 5.0
|
|
|
|
|
width:
|
|
|
|
|
- 4.0
|
|
|
|
|
- 1.0
|
|
|
|
|
level: 0
|
|
|
|
|
adjacency:
|
|
|
|
|
- da1
|
|
|
|
|
- c
|
|
|
|
|
|
|
|
|
|
# SLEEPING AREAS - Anonymous neighborhoods (5 total, 2 ground + 3 first)
|
|
|
|
|
n:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: bedroom
|
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
|
|
|
name: Neighborhood
|
|
|
|
|
size:
|
|
|
|
|
- 60.0
|
|
|
|
|
- 8.0
|
|
|
|
|
width:
|
|
|
|
|
- 5.0
|
|
|
|
|
- 1.0
|
|
|
|
|
proportion:
|
|
|
|
|
- 2.0
|
|
|
|
|
- 0.6
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
count: 5
|
|
|
|
|
|
|
|
|
|
# GROUND FLOOR - Activity Spaces
|
|
|
|
|
ws1:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: living
|
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
|
|
|
name: Workshop Space
|
|
|
|
|
size:
|
|
|
|
|
- 40.0
|
|
|
|
|
- 6.0
|
|
|
|
|
width:
|
|
|
|
|
- 5.0
|
|
|
|
|
- 1.0
|
|
|
|
|
proportion:
|
|
|
|
|
- 1.8
|
|
|
|
|
- 0.5
|
|
|
|
|
level: 0
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
- o
|
|
|
|
|
|
|
|
|
|
# MEETING ROOMS - Anonymous interchangeable (3 total)
|
|
|
|
|
m:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: living
|
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
|
|
|
name: Meeting Room
|
|
|
|
|
size:
|
|
|
|
|
- 10.0
|
|
|
|
|
- 2.0
|
|
|
|
|
width:
|
|
|
|
|
- 2.5
|
|
|
|
|
- 0.5
|
|
|
|
|
level: 0
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
count: 3
|
2026-07-31 00:16:12 +01:00
|
|
|
co_locate:
|
|
|
|
|
- ef1
|
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
|
|
|
|
|
|
|
|
# GROUND FLOOR - Service Areas
|
|
|
|
|
# BATHROOMS - Ground floor (3 total)
|
|
|
|
|
t:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: toilet
|
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
|
|
|
name: Bathroom
|
|
|
|
|
size:
|
|
|
|
|
- 6.0
|
|
|
|
|
- 1.5
|
|
|
|
|
width:
|
|
|
|
|
- 2.0
|
|
|
|
|
- 0.5
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
count: 6 # 3 ground + 3 first floor
|
|
|
|
|
|
|
|
|
|
la1:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: utility
|
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
|
|
|
name: Laundry Room
|
|
|
|
|
size:
|
|
|
|
|
- 20.0
|
|
|
|
|
- 4.0
|
|
|
|
|
width:
|
|
|
|
|
- 3.0
|
|
|
|
|
- 0.8
|
|
|
|
|
level: 0
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
2026-07-31 00:16:12 +01:00
|
|
|
# homemaker-py-1s3: laundry and plant/M&E rooms are both "back of house"
|
|
|
|
|
# utility space — a common real loose-fit pairing.
|
|
|
|
|
co_locate:
|
|
|
|
|
- me1
|
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
|
|
|
|
§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
|
|
|
st1:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: utility
|
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
|
|
|
name: Ground Floor Storage
|
|
|
|
|
size:
|
|
|
|
|
- 22.0
|
|
|
|
|
- 4.0
|
|
|
|
|
width:
|
|
|
|
|
- 3.0
|
|
|
|
|
- 0.8
|
|
|
|
|
level: 0
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
|
|
|
|
|
me1:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: utility
|
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
|
|
|
name: Mechanical/Electrical Room
|
|
|
|
|
size:
|
|
|
|
|
- 25.0
|
|
|
|
|
- 4.0
|
|
|
|
|
width:
|
|
|
|
|
- 3.5
|
|
|
|
|
- 0.8
|
|
|
|
|
level: 0
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
2026-07-31 00:16:12 +01:00
|
|
|
co_locate:
|
|
|
|
|
- la1
|
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
|
|
|
|
|
|
|
|
# STAFF OFFICES - Anonymous (2 total)
|
§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
|
|
|
of:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: bedroom
|
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
|
|
|
name: Staff Office
|
|
|
|
|
size:
|
|
|
|
|
- 12.5
|
|
|
|
|
- 2.5
|
|
|
|
|
width:
|
|
|
|
|
- 2.5
|
|
|
|
|
- 0.5
|
|
|
|
|
level: 0
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
count: 2
|
|
|
|
|
|
|
|
|
|
# FIRST FLOOR - Community Areas
|
|
|
|
|
li1:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: living
|
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
|
|
|
name: Library Corner
|
|
|
|
|
size:
|
|
|
|
|
- 20.0
|
|
|
|
|
- 4.0
|
|
|
|
|
width:
|
|
|
|
|
- 3.5
|
|
|
|
|
- 0.8
|
|
|
|
|
level: 1
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
|
|
|
|
|
# FIRST FLOOR - Individual Rooms (10 anonymous rooms)
|
|
|
|
|
r:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: bedroom
|
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
|
|
|
name: Individual Room
|
|
|
|
|
size:
|
|
|
|
|
- 10.0
|
|
|
|
|
- 2.0
|
|
|
|
|
width:
|
|
|
|
|
- 2.5
|
|
|
|
|
- 0.5
|
|
|
|
|
level: 1
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
count: 10
|
|
|
|
|
|
|
|
|
|
# FIRST FLOOR - Storage
|
§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
|
|
|
st2:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: utility
|
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
|
|
|
name: First Floor Storage
|
|
|
|
|
size:
|
|
|
|
|
- 18.0
|
|
|
|
|
- 3.5
|
|
|
|
|
width:
|
|
|
|
|
- 3.0
|
|
|
|
|
- 0.8
|
|
|
|
|
level: 1
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
|
|
|
|
|
ut1:
|
§39.7: access requirements become a declared `usage:` attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.
usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.
Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.
- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
retype changes the class automatically. 51 sites assign leaf.type, and
share/share_type plus the r5a resurrection are the precedent for why
leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
fitness.access and the public-access check likewise. fitness._t0 is DELETED --
no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
and layout preserved.
MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
harbor-house 18 (9%) -> 79 (39%) inaccessible fails 0 -> 4
health-centre 12 (8%) -> 59 (40%) inaccessible fails 2 -> 3
maple-court 53 (17%) -> 123 (39%) inaccessible fails 1 -> 5
Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.
Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.
350 passed (+5 new), same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 13:39:41 +00:00
|
|
|
usage: utility
|
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
|
|
|
name: Utilities Closet
|
|
|
|
|
size:
|
|
|
|
|
- 14.0
|
|
|
|
|
- 3.0
|
|
|
|
|
width:
|
|
|
|
|
- 2.5
|
|
|
|
|
- 0.6
|
|
|
|
|
level: 1
|
|
|
|
|
adjacency:
|
|
|
|
|
- c
|
|
|
|
|
|
|
|
|
|
# Building constraints
|
|
|
|
|
storey_minimum: 2
|
|
|
|
|
storey_limit: 3
|
|
|
|
|
force_roof_garden: 0
|
|
|
|
|
|
|
|
|
|
# Circulation ratio (allow more circulation for larger building)
|
|
|
|
|
ratio_circulation:
|
|
|
|
|
- 0.08
|
|
|
|
|
- 0.15
|
|
|
|
|
|
|
|
|
|
# Outside space ratio (courtyard requirement)
|
|
|
|
|
ratio_outside:
|
|
|
|
|
- 0.15
|
|
|
|
|
- 0.10
|
|
|
|
|
|
|
|
|
|
# Staircase requirements (main + secondary)
|
|
|
|
|
staircase_min: 2
|
|
|
|
|
staircase_max: 2
|
|
|
|
|
|
|
|
|
|
# Economic parameters
|
|
|
|
|
value_inside: 300.0
|
|
|
|
|
value_circulation: 50.0
|
|
|
|
|
value_outside: 100.0
|
|
|
|
|
value_supported: 300.0
|