homemaker-layout/examples/harbor-house/patterns.config

267 lines
4 KiB
Text
Raw Normal View History

---
# 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:
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:
name: Entrance Foyer
size:
- 15.0
- 3.0
width:
- 3.0
- 0.5
level: 0
adjacency:
- c
# 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
da1:
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:
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:
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:
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:
name: Meeting Room
size:
- 10.0
- 2.0
width:
- 2.5
- 0.5
level: 0
adjacency:
- c
count: 3
co_locate:
- ef1
# GROUND FLOOR - Service Areas
# BATHROOMS - Ground floor (3 total)
t:
name: Bathroom
size:
- 6.0
- 1.5
width:
- 2.0
- 0.5
adjacency:
- c
count: 6 # 3 ground + 3 first floor
la1:
name: Laundry Room
size:
- 20.0
- 4.0
width:
- 3.0
- 0.8
level: 0
adjacency:
- c
# 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
§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:
name: Ground Floor Storage
size:
- 22.0
- 4.0
width:
- 3.0
- 0.8
level: 0
adjacency:
- c
me1:
name: Mechanical/Electrical Room
size:
- 25.0
- 4.0
width:
- 3.5
- 0.8
level: 0
adjacency:
- c
co_locate:
- la1
# 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:
name: Staff Office
size:
- 12.5
- 2.5
width:
- 2.5
- 0.5
level: 0
adjacency:
- c
count: 2
# FIRST FLOOR - Community Areas
li1:
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:
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:
name: First Floor Storage
size:
- 18.0
- 3.5
width:
- 3.0
- 0.8
level: 1
adjacency:
- c
ut1:
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