From c9b9eafef669a3a5f9d8117373ed4f8a5de34bf7 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 28 Aug 2026 23:14:21 +0000 Subject: [PATCH] Owner's daylight ruling: corridors need it; retract the 61% headline Ruling: corridors need daylight. Only rooms not occupied from day to day -- a cupboard, a store, a plant room -- do without it. That overturns the classification 38.8 and 38.9 rested on. Those sections exempted internal circulation, covered courtyards, WCs, laundries and reception on my inference rather than any ruling. None are exempt: a corridor is occupied all day every day, a waiting room likewise, a laundry is a room people spend time in, a sterilisation room is a workplace. Re-measured with the classification READ FROM THE CORPUS (a space is exempt exactly when its own patterns.config declares crinkliness: none) instead of inferred: 24 of 271 crinkliness fails (9%) were not defects -- not 136 (50%), not 61%. Overstated by about six times. - uncrinkliness_circulation stays at [5/6, 1.1/3]. 38.10 called its equality with the habitable target the purest case of an untuned value; it is not a bug, it is the correct answer reached by default, since corridors want daylight on the same terms as rooms. - corpus declarations narrowed 18 -> 14. usage: utility was too coarse and swept in Laundry Rooms and a Sterilisation Room. What remains is storage, plant/mechanical, utilities closets and a records room. - audit_crinkliness_truth.py rebuilt to read the classification from the configs rather than infer it from usage:, so it cannot drift from the ruling again. - 38.8/38.9's inflated figures flagged in place, with 38.11 carrying the correction. What survives, none of it dependent on the classification: the 38.6 critique of the three modes; usage_daylight being mis-keyed; the 38.8 A/B yardstick being wrong; and the per-space crinkliness mechanism itself. ssz's opening measurement was right but its reading was wrong -- under this ruling a buried leaf usually IS a defect, so scoring it zero is largely correct. The narrowed remnant is that the score is FLAT rather than low, so two equally-buried layouts cannot be ranked. Filed as homemaker-py-9gj; it is a search-mechanics problem, not a calibration one. Lint at parity (46); tests 369 passed, 2 pre-existing failures (ut5's stale baseline and 1ue), both failing identically before this change. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB --- .beads/issues.jsonl | 3 +- DESIGN.md | 92 ++++++++++++++++++++++-- examples/harbor-house-l0/patterns.config | 1 - examples/harbor-house/patterns.config | 1 - examples/health-centre/patterns.config | 1 - examples/maple-court/patterns.config | 1 - experiments/audit_crinkliness_truth.py | 63 +++++++++------- 7 files changed, 127 insertions(+), 35 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index e90325d..e3d6dae 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -5,7 +5,7 @@ {"_type":"issue","id":"homemaker-py-sel","title":"Usage prefixes (b/t/l/k) are a second implicit namespace: 4 corpus rooms get another room's connectivity rules from their spelling","description":"§39.4 separated programme codes from the GENERIC structural types (C/O/S). It did not touch the other namespace sharing the first character: the USAGE prefixes b=bedroom, t=toilet, l=living, k=kitchen. These classify programme codes by first letter and are still prefix-based BY DESIGN (it is how Urb encodes room usage, and unlike the generic rule they never discard a requirement) -- but they are not inert.\\n\\ngraph.has_circulation deletes graph edges from them: a 'bedroom' loses its edges to living/kitchen/bedroom/toilet, a 'toilet' loses its edges to outside/living/kitchen/toilet, and b/t keep their LEAST popular circulation neighbour while l/k keep their MOST popular. fitness.access and the public-access check read them too. So a code that picks one up by accident is silently given another room's connectivity rules -- and connectivity is exactly where §38 located the residual.\\n\\nFour corpus rooms are misclassified by spelling alone:\\n la1 'Laundry Room' -\u003e living (harbor-house, harbor-house-l0, maple-court)\\n li1 'Library Corner' -\u003e living (harbor-house, maple-court)\\n br1 'Staff Room' -\u003e bedroom (health-centre)\\n tr1 'Treatment Room' -\u003e toilet (health-centre)\\n\\nMeasured on a constructed health-centre seed: tr1 (as a toilet) has its edge to the adjacent outside space O stripped from the circulation graph; br1 (as a bedroom) has its edge to t10 'Staff WC' stripped. Both feed has_circulation and therefore the 'N inaccessible usable space' / 'level N not connected' fails.\\n\\nReport it with: python experiments/audit_programme_config.py (usage-prefix section).","design":"FINAL SHAPE. usage is a plain ATTRIBUTE of the space definition, mandatory on every declared code, no prefix fallback and NO mapping table.\n\n spaces:\n ws1:\n name: Workshop Space # free text, building-specific\n usage: living # controlled, drives engine behaviour\n\nThe earlier 'usage_classes:' indirection table (binding author-coined names like craft-\u003eliving) is WITHDRAWN. It was wrong three ways: (a) an indirect name-\u003ebehaviour mapping living apart from the thing it describes is exactly the shape of the first-character prefix rule that §39 exists to remove, not relocate; (b) it is inconsistent with the schema — every other space property is a plain attribute (name/size/width/proportion/adjacency/level/requires_below/count/share/interchange/co_locate) and no key in patterns.config is an indirection table; (c) the need it served is already met, because 'programmes are building specific' is about what a room is CALLED and name: is already free text, whereas usage: records ACCESS REQUIREMENTS, which are not building-specific — a craft room and a lounge have the same ones, which is the entire reason the key exists.\n\nRULE THAT FALLS OUT: a usage value exists if and only if the engine treats it differently somewhere. Config selects among behaviours; it cannot invent them. A genuinely new access class means writing code, and at that point the value joins the controlled set for everyone. utility passes this test — not on edge-stripping (identical to bedroom today) but because it is intended to drive derive_interchange_classes; distinct behaviour in a second subsystem is a real difference, an alias is not.\n\nVocabulary: living, kitchen, bedroom, toilet, utility, none. Missing usage on a declared code = load error naming the code. Unknown value = load error.\n\nMutation-safety (the original objection): usage is CODE-level, so usage_of(leaf.type) is looked up fresh on every read exactly as size/width/adjacency already are. Never stamp it on a leaf — 51 sites assign leaf.type, and share/share_type plus the r5a resurrection bug are the precedent for why leaf-level attributes go stale.\n\nAssignments for all 52 corpus codes: experiments/usage_map_proposal.yaml (living 12, bedroom 17, utility 11, toilet 7, kitchen 2, none 3; zero unresolved).","acceptance_criteria":"A programme can declare a room's usage explicitly; the prefix rule applies only where nothing is declared; audit_programme_config reports no unintended usage classification across the corpus; re-baselined with an A/B.","notes":"ALL 52 CORPUS CODES NOW ASSIGNED (experiments/usage_map_proposal.yaml): living 12, bedroom 17, utility 11, toilet 7, kitchen 2, none 3. Zero unresolved.\n\nRulings received: li1 Library Corner + br1 Staff Room -\u003e living (same access requirements); tr1 Treatment Room -\u003e bedroom; la1 Laundry -\u003e utility; zt1 Sterilisation -\u003e utility; ph1 Pharmacy -\u003e bedroom (private room, not public, like an office); n 'Neighborhood' -\u003e bedroom (a communal sleeping area, much like a dormitory); gh1 Greenhouse -\u003e living (grows plants but a living area like a conservatory); ws1 Workshop -\u003e living CONDITIONALLY (building-specific: communal craft room vs maintenance area; both corpus programmes carrying it are communal living facilities).\n\nDESIGN DECISION 1 — utility is a DISTINCT value, not an alias for bedroom. Same edge-stripping today (identical access requirements) but separately declared, because (a) they are very different uses and the config should read truthfully, and (b) it gives programme.derive_interchange_classes (§13/§26, homemaker-py-9o5) a natural axis: bedroom-class and utility-class leaves could be interchangeable DURING search and collapse to their real use at scoring time — exactly the superposition relaxation that machinery already implements. Worth building the usage key with that hook in mind.\n\nDESIGN DECISION 2 — vocabulary controlled but NOT closed. The earlier 'closed enum, unknown value errors' recommendation is withdrawn ('programmes are building specific, so it would be nice to have a controlled vocabulary, but not entirely necessary'). Proposed: the six known names drive engine behaviour; a programme may coin its own (usage: craft) provided it binds it in the same file via usage_classes: {craft: living}. An unbound name is a load error, so naming stays free without ever letting an unrecognised usage fall through to a silent default.\n\nVERIFIED — Brand adjacency point is NOT an engine bug. fitness._evaluate_full runs check_adjacency against graph_base_pre, the UNFILTERED graph, so a declared adjacency requirement is satisfied by a neighbouring room regardless of what has_circulation strips. The stripping only denies ROUTING, which is correct. So 'a toilet adjacent to a bedroom is a positive even if there is no door' is already expressible -- but it is only scored where DECLARED, and 3 of 4 real programmes never declare it: only programme-house has t1 -\u003e adjacency [b1]. harbor-house (t vs r/n), maple-court (t/tt vs r/n) and health-centre (t9/t10 vs tr1) do not. Filed separately as homemaker-py-adj.","status":"closed","priority":1,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-26T10:06:54Z","created_by":"Claude","updated_at":"2026-08-26T13:38:20Z","closed_at":"2026-08-26T13:38:20Z","close_reason":"SHIPPED (DESIGN.md §39.7). usage: is a mandatory plain attribute of the space definition; vocabulary living/kitchen/bedroom/toilet/utility/none; missing or unknown is a load error from both parse paths. Code-level so it survives retype, never stamped on a leaf. has_circulation, fitness.access and the public-access check all key on declared usage; fitness._t0 deleted — no first-character type test remains anywhere. All 107 corpus entries migrated. MEASURED: connectivity model was ~4x too permissive; edges trimmed prefix-inferred vs declared, 3 seeds: harbor 18(9%)-\u003e79(39%), health-centre 12(8%)-\u003e59(40%), maple 53(17%)-\u003e123(39%); inaccessible fails 0-\u003e4, 2-\u003e3, 1-\u003e5. Harbor re-baseline seed 1/20k: 58 (15h/43s) -\u003e 61 (16h/45s), now reporting inaccessible-usable-space x2 plus level 0 and level 1 not connected — the count rose because the objective got honest.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-ut5","title":"Update the 2v1 acceptance target: harbor's 15-fail reference was measured pre-ju3 against the 32-instance effective programme","description":"DESIGN.md 38.7 fixes the acceptance test for homemaker-py-2v1 as 'harbor-house reaches its known 15-fail floor in materially fewer than 1.7M evals, and without level 0/1 not connected'. That 15-fail figure comes from evolved-3M-nols-3, measured before homemaker-py-ju3 against the 32-instance EFFECTIVE programme (cr1/of/st1/st2 silently dropped or mis-parameterised). Against the real 37-instance programme the number will differ, so the target as written is not measurable any more.\\n\\nNeeded: migrate evolved-3M*.dom with experiments/migrate_ju3_rename.py, rescore against the renamed programme, and restate the 2v1 acceptance figure. The 39.3 re-baseline (55 fails, seed 1, 20k evals) is the new near-term reference but is not the long-budget floor.","acceptance_criteria":"evolved-3M*.dom committed and migrated; its post-ju3 fail count recorded in DESIGN.md; the 2v1 acceptance figure restated against it.","status":"open","priority":1,"issue_type":"task","owner":"noreply@anthropic.com","created_at":"2026-08-26T09:05:23Z","created_by":"Claude","updated_at":"2026-08-26T09:05:23Z","comments":[{"id":"01a04a88-f365-774a-9f49-f6bda0dec0dc","issue_id":"homemaker-py-ut5","author":"Claude","text":"Now concrete and reproducible, since the owner committed the evolved-3M*.dom fixtures (0d4ae7a).\n\ntests/test_collapse_insearch.py::test_collapse_insearch_reproduces_94g_finish_time_result hard-codes 'assert len(f_base) == 15' against examples/harbor-house/evolved-3M.dom. Measured now:\n\n 86 fails at 0d4ae7a (post-39.4, before the ssz crinkliness change)\n 81 fails at 055d710 (after crinkliness: none on utility spaces)\n\nagainst the test's 15. The gap is the 39.4 namespace fix: the 15 was measured when harbor's effective programme was 32 instances because codes like cr1 were being read as generic circulation. The remaining 5 is this session's ssz change, in the expected direction and for the expected reason (utility spaces no longer emit crinkliness fails).\n\nSo this issue now has a failing test attached to it, which is the natural place to land the restated figure.","created_at":"2026-08-28T22:41:24Z"}],"dependency_count":0,"dependent_count":0,"comment_count":1} {"_type":"issue","id":"homemaker-py-hxi","title":"Buried circulation and outside space are negative-value: search is rewarded for deleting the circulation spine","description":"Direct consequence of the zero-exposure bug. Measured on a constructed harbor-house seed: deleting a buried O leaf improved the raw score 85x and removed 7 fails; deleting a buried C leaf improved it 62x and removed 6 fails. Programme rooms are held in place ONLY by the missing-space fail cascade, not by contributing value -- deleting a buried k1/da1/m costs +15 fails, so they stay, but nothing positive keeps them. Circulation and outside leaves carry no missing-space requirement, so nothing keeps them at all. Observed live: in a 20k-eval harbor-house run, undivide/core_undivide account for a large share of recorded improvements (16 occurrences in the log) -- the search is literally deleting circulation to score better. This explains three prior negative results as a single mechanism: 18 graded circulation-connectivity (a tie-break signal cannot beat a 60x scalar gradient), 21/22 bridge_circulation (the operator inserts corridor leaves the objective immediately punishes), and the 'level N not connected' hard fails surviving \u003e1M evals in the 3M run.","notes":"Depends on the zero-exposure fix; may need no separate fix if (a)/(c) there restores a value gradient for circulation. Worth re-running the 18 and 21/22 A/Bs afterwards -- both may have been measuring a broken gradient rather than a bad idea.","status":"open","priority":1,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-25T23:14:40Z","created_by":"Claude","updated_at":"2026-08-25T23:14:40Z","dependencies":[{"issue_id":"homemaker-py-hxi","depends_on_id":"homemaker-py-ssz","type":"blocks","created_at":"2026-08-25T23:15:12Z","created_by":"Claude","metadata":"{}"},{"issue_id":"homemaker-py-hxi","depends_on_id":"homemaker-py-2v1","type":"blocks","created_at":"2026-08-26T07:37:47Z","created_by":"Claude","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"homemaker-py-ssz","title":"Zero-exposure leaves score hard quality=0: the objective assigns no value to any interior room","description":"fitness.quality_uncrinkliness returns a hard 0.0 when a leaf has no daylit wall (area_outside==0 =\u003e crink==0 =\u003e 'if not crink: return 0.0'). Because evaluate_leaf MULTIPLIES factors into quality, and process_storey accumulates 'value += quality * rate * area', such a leaf contributes EXACTLY ZERO value while still adding cost. Measured on the full default construction stack (leaf_sharing, depth_balanced, interior_outside, collapse_insearch), 3 seeds each: harbor-house 46% of interior leaves, health-centre 45%, maple-court 56% are zero-exposure. On a converged 20k-eval harbor-house run (seed 1, 57 fails) 14 of 17 crinkliness fails are zero-exposure, and ~470 m2 of the 721 m2 ground floor plate sits at zero value. This is the mathematically consistent limit of the gaussian (1/crink -\u003e inf), so it is a faithful port, not a porting bug -- but it means the objective's gradient does not describe a good building.","design":"Options, none yet chosen: (a) floor the factor at a small epsilon instead of 0 so buried leaves keep a value gradient and remain rankable; (b) make the gaussian one-sided (clip to 1.0 on the compact side) so being LESS exposed than target is not punished as hard as being over-exposed -- architecturally, a compact well-insulated room is not a defect; (c) exempt circulation/store types from the daylight requirement entirely (uncrinkliness_circulation currently uses the same [5/6, 1.1/3] as habitable rooms, so internal corridors -- completely normal architecture -- are guaranteed failures). Any change here invalidates prior fail-count baselines, so it needs its own A/B and a DESIGN.md section.","acceptance_criteria":"A/B on harbor-house + maple-court at fixed budget showing the chosen variant lowers hard-fail count without inflating soft; DESIGN.md section recording the result; prior baselines re-stated under the new objective.","status":"in_progress","priority":1,"issue_type":"bug","assignee":"Claude","owner":"noreply@anthropic.com","created_at":"2026-08-25T23:14:40Z","created_by":"Claude","updated_at":"2026-08-26T16:34:22Z","started_at":"2026-08-26T16:34:22Z","dependencies":[{"issue_id":"homemaker-py-ssz","depends_on_id":"homemaker-py-2v1","type":"blocks","created_at":"2026-08-26T07:37:47Z","created_by":"Claude","metadata":"{}"}],"comments":[{"id":"01a03ef6-9e45-7a1d-9f3c-3b3f0bd8a98f","issue_id":"homemaker-py-ssz","author":"Claude","text":"Diagnosis reframed and implementation landed (189efdb, DESIGN.md §38.8).\n\n§38.6's null was an artefact of the modes, not evidence about the objective: quality_uncrinkliness reaches `if not crink` before any mode logic that matters, so floor gave buried leaves 0.01, compact_ok contradicted itself (announced compact-is-fine, then returned the floor for the most compact case of all), and exempt_circulation reached at most a third of them. Rescue rates 0%/0%/0%/21-33%. §38.6 also used the pre-§39.4 prefix rule, sweeping programme rooms like cr1 in as circulation.\n\nReal finding: two thirds of buried leaves are spaces that architecturally do not want a window (stores, WCs, plant, corridors, covered courtyards), scored identically with a windowless bedroom. New mode usage_daylight keys the requirement on the declared usage. Fixed-budget search A/B running now; arms are re-scored under stock urb so the permissive modes cannot win by deleting a fail category.","created_at":"2026-08-26T16:45:45Z"},{"id":"01a03f38-06bd-7bb8-8f8b-8144c2ac3364","issue_id":"homemaker-py-ssz","author":"Claude","text":"Fixed-budget A/B done (budget 3000, 3 seeds, both programmes, arms scored under stock urb). NOT A PASS, and n=3 cannot decide it.\n\nPaired hard-fail deltas vs urb -- usage_daylight harbor [0,-1,-10], maple [0,+2,-10]. The whole signal is seed 2 in both programmes, and seed 2 is the seed where stock itself does worst. Two seeds in three are flat or slightly worse. On that seed the soft count rises as much as hard falls (harbor -10h/+9s, maple -10h/+15s); totals harbor 62-\u003e61, maple 120-\u003e125.\n\nSince arms are stock-scored, that is a real trade of hard for soft, not a relabelling. Under the tiered comparator (n_hard primary) it is progress; under this issue's acceptance criterion ('without inflating soft') it is not. That tension is gvb's question too.\n\nusage_daylight stays default off. Higher-power run launched: urb vs usage_daylight only, 10 seeds, both programmes.\n\nDecided regardless of the search A/B: the diagnostic half. Daylight is demanded of two thirds of the buried population that architecturally does not want it, and §38.6's contrary null was an artefact of three modes that never touched those leaves.","created_at":"2026-08-26T17:57:11Z"},{"id":"01a04a89-3805-7419-af9b-7b31a110d898","issue_id":"homemaker-py-ssz","author":"Claude","text":"Shipped the declared per-space crinkliness mechanism (055d710, DESIGN.md §38.10) per the owner's ruling that the daylight requirement is already defined in the crinkliness -- no separate attribute, no usage-keying.\n\nCrinkliness was the only leaf quality factor with no per-space target (size/width/proportion all have one). A space now declares crinkliness: none / [t,s], or omits it for the global target. clips the compact side only, so a store may be buried but not be a starfish. Backward compatible: absent key = today's behaviour, so behaviour changes only where a config declares.\n\n18 corpus spaces migrated (usage: utility). Crinkliness fails 271 -\u003e 243; not-defects 136 (50%) -\u003e 108 (44%).\n\nREMAINING, and needs a ruling before ssz can close: the last 108 phantom fails are two populations with no spaces: entry --\n generic C (internal circulation): 85, key uncrinkliness_circulation\n generic O/S (covered outside, sahn): 23, falls through to uncrinkliness\n\nuncrinkliness_circulation exists as its own key and holds [5/6, 1.1/3], byte-identical to the habitable target -- a key created so corridors could differ, never given a different value. It is now settable to none (tested) but the default is left alone: corridors were not among the groups ruled on and this is 63% of the remainder.","created_at":"2026-08-28T22:41:42Z"},{"id":"01a04a89-964c-7107-b9f6-7597540a9c59","issue_id":"homemaker-py-ssz","author":"Claude","text":"Correction to the previous comment: a shell backtick ate a word. The sentence\nshould read:\n\n `crinkliness: none` clips the compact side ONLY, it does not switch the\n factor off. Over-exposure is still penalised, because a crinkly leaf costs\n envelope whatever it holds. So a store may be buried, but a store may not be\n a starfish.\n\nEverything else in that comment stands.","created_at":"2026-08-28T22:42:06Z"}],"dependency_count":1,"dependent_count":2,"comment_count":4} +{"_type":"issue","id":"homemaker-py-ssz","title":"Zero-exposure leaves score hard quality=0: the objective assigns no value to any interior room","description":"fitness.quality_uncrinkliness returns a hard 0.0 when a leaf has no daylit wall (area_outside==0 =\u003e crink==0 =\u003e 'if not crink: return 0.0'). Because evaluate_leaf MULTIPLIES factors into quality, and process_storey accumulates 'value += quality * rate * area', such a leaf contributes EXACTLY ZERO value while still adding cost. Measured on the full default construction stack (leaf_sharing, depth_balanced, interior_outside, collapse_insearch), 3 seeds each: harbor-house 46% of interior leaves, health-centre 45%, maple-court 56% are zero-exposure. On a converged 20k-eval harbor-house run (seed 1, 57 fails) 14 of 17 crinkliness fails are zero-exposure, and ~470 m2 of the 721 m2 ground floor plate sits at zero value. This is the mathematically consistent limit of the gaussian (1/crink -\u003e inf), so it is a faithful port, not a porting bug -- but it means the objective's gradient does not describe a good building.","design":"Options, none yet chosen: (a) floor the factor at a small epsilon instead of 0 so buried leaves keep a value gradient and remain rankable; (b) make the gaussian one-sided (clip to 1.0 on the compact side) so being LESS exposed than target is not punished as hard as being over-exposed -- architecturally, a compact well-insulated room is not a defect; (c) exempt circulation/store types from the daylight requirement entirely (uncrinkliness_circulation currently uses the same [5/6, 1.1/3] as habitable rooms, so internal corridors -- completely normal architecture -- are guaranteed failures). Any change here invalidates prior fail-count baselines, so it needs its own A/B and a DESIGN.md section.","acceptance_criteria":"A/B on harbor-house + maple-court at fixed budget showing the chosen variant lowers hard-fail count without inflating soft; DESIGN.md section recording the result; prior baselines re-stated under the new objective.","status":"in_progress","priority":1,"issue_type":"bug","assignee":"Claude","owner":"noreply@anthropic.com","created_at":"2026-08-25T23:14:40Z","created_by":"Claude","updated_at":"2026-08-26T16:34:22Z","started_at":"2026-08-26T16:34:22Z","dependencies":[{"issue_id":"homemaker-py-ssz","depends_on_id":"homemaker-py-2v1","type":"blocks","created_at":"2026-08-26T07:37:47Z","created_by":"Claude","metadata":"{}"}],"comments":[{"id":"01a03ef6-9e45-7a1d-9f3c-3b3f0bd8a98f","issue_id":"homemaker-py-ssz","author":"Claude","text":"Diagnosis reframed and implementation landed (189efdb, DESIGN.md §38.8).\n\n§38.6's null was an artefact of the modes, not evidence about the objective: quality_uncrinkliness reaches `if not crink` before any mode logic that matters, so floor gave buried leaves 0.01, compact_ok contradicted itself (announced compact-is-fine, then returned the floor for the most compact case of all), and exempt_circulation reached at most a third of them. Rescue rates 0%/0%/0%/21-33%. §38.6 also used the pre-§39.4 prefix rule, sweeping programme rooms like cr1 in as circulation.\n\nReal finding: two thirds of buried leaves are spaces that architecturally do not want a window (stores, WCs, plant, corridors, covered courtyards), scored identically with a windowless bedroom. New mode usage_daylight keys the requirement on the declared usage. Fixed-budget search A/B running now; arms are re-scored under stock urb so the permissive modes cannot win by deleting a fail category.","created_at":"2026-08-26T16:45:45Z"},{"id":"01a03f38-06bd-7bb8-8f8b-8144c2ac3364","issue_id":"homemaker-py-ssz","author":"Claude","text":"Fixed-budget A/B done (budget 3000, 3 seeds, both programmes, arms scored under stock urb). NOT A PASS, and n=3 cannot decide it.\n\nPaired hard-fail deltas vs urb -- usage_daylight harbor [0,-1,-10], maple [0,+2,-10]. The whole signal is seed 2 in both programmes, and seed 2 is the seed where stock itself does worst. Two seeds in three are flat or slightly worse. On that seed the soft count rises as much as hard falls (harbor -10h/+9s, maple -10h/+15s); totals harbor 62-\u003e61, maple 120-\u003e125.\n\nSince arms are stock-scored, that is a real trade of hard for soft, not a relabelling. Under the tiered comparator (n_hard primary) it is progress; under this issue's acceptance criterion ('without inflating soft') it is not. That tension is gvb's question too.\n\nusage_daylight stays default off. Higher-power run launched: urb vs usage_daylight only, 10 seeds, both programmes.\n\nDecided regardless of the search A/B: the diagnostic half. Daylight is demanded of two thirds of the buried population that architecturally does not want it, and §38.6's contrary null was an artefact of three modes that never touched those leaves.","created_at":"2026-08-26T17:57:11Z"},{"id":"01a04a89-3805-7419-af9b-7b31a110d898","issue_id":"homemaker-py-ssz","author":"Claude","text":"Shipped the declared per-space crinkliness mechanism (055d710, DESIGN.md §38.10) per the owner's ruling that the daylight requirement is already defined in the crinkliness -- no separate attribute, no usage-keying.\n\nCrinkliness was the only leaf quality factor with no per-space target (size/width/proportion all have one). A space now declares crinkliness: none / [t,s], or omits it for the global target. clips the compact side only, so a store may be buried but not be a starfish. Backward compatible: absent key = today's behaviour, so behaviour changes only where a config declares.\n\n18 corpus spaces migrated (usage: utility). Crinkliness fails 271 -\u003e 243; not-defects 136 (50%) -\u003e 108 (44%).\n\nREMAINING, and needs a ruling before ssz can close: the last 108 phantom fails are two populations with no spaces: entry --\n generic C (internal circulation): 85, key uncrinkliness_circulation\n generic O/S (covered outside, sahn): 23, falls through to uncrinkliness\n\nuncrinkliness_circulation exists as its own key and holds [5/6, 1.1/3], byte-identical to the habitable target -- a key created so corridors could differ, never given a different value. It is now settable to none (tested) but the default is left alone: corridors were not among the groups ruled on and this is 63% of the remainder.","created_at":"2026-08-28T22:41:42Z"},{"id":"01a04a89-964c-7107-b9f6-7597540a9c59","issue_id":"homemaker-py-ssz","author":"Claude","text":"Correction to the previous comment: a shell backtick ate a word. The sentence\nshould read:\n\n `crinkliness: none` clips the compact side ONLY, it does not switch the\n factor off. Over-exposure is still penalised, because a crinkly leaf costs\n envelope whatever it holds. So a store may be buried, but a store may not be\n a starfish.\n\nEverything else in that comment stands.","created_at":"2026-08-28T22:42:06Z"},{"id":"01a04aa6-d83f-7513-ada7-4a3fee8e804a","issue_id":"homemaker-py-ssz","author":"Claude","text":"RETRACTION. Owner's ruling: corridors need daylight; only rooms not occupied\nfrom day to day (cupboard, store, plant room) do without it.\n\nThat overturns the classification my 61% headline rested on. I had exempted\ninternal circulation, covered courtyards, WCs, laundries and reception on my own\ninference; none of those are exempt. Re-measured with the classification read\nfrom the corpus rather than guessed:\n\n 24 of 271 crinkliness fails (9%) were not defects -- not 136 (50%), not 61%.\n\nI overstated it by about six times by inventing a classification instead of\nasking for one.\n\nConsequences:\n - uncrinkliness_circulation stays at [5/6, 1.1/3]. Its equality with the\n habitable target is the CORRECT answer, not an untuned value: corridors want\n daylight on the same terms as rooms.\n - corpus declarations narrowed 18 -\u003e 14. usage: utility was too coarse a\n proxy; it swept in Laundry Rooms and a Sterilisation Room, which are\n occupied. What remains is storage, plant/mechanical, utilities closets and a\n records room.\n\nWhat survives unchanged, none of it dependent on the classification: the §38.6\ncritique of the three modes (facts about the code); usage_daylight being\nmis-keyed; the §38.8 A/B yardstick being wrong; and the per-space crinkliness\nmechanism itself, which is the owner's design.\n\nWhat this does to the issue as a whole: the opening measurement (45-56% of\ninterior leaves are zero-exposure) was right, but the reading was wrong. Under\nthis ruling a buried leaf usually IS a defect, so scoring it zero is largely\ncorrect. What remains of the complaint is narrower and is about search mechanics\nrather than truth -- a hard 0.0 cannot rank two bad layouts against each other.\nFiling that separately; it is not the calibration fault this issue spent its\nlength chasing.","created_at":"2026-08-28T23:14:03Z"}],"dependency_count":1,"dependent_count":2,"comment_count":5} {"_type":"issue","id":"homemaker-py-tdp","title":"Frontage-budget feasibility bound: harbor-house and maple-court are ~3x short of the exposed wall their own crinkliness constraint demands","description":"Closed-form bound, no search needed. Crinkliness fails when 1/crink \u003e 1.6202 (solving gaussian(x,1,5/6,1.1/3)=FAIL_THRESHOLD), and crink = L*h/A, so every interior leaf needs exposed wall length L \u003e= A/(1.6202*h) -- per storey, A_storey/4.86 metres at h=3. Supply vs demand per storey: harbor-house 54m supplied / 148m needed (2.7x short); maple-court 56m / 162m (2.9x short); health-centre 43m / 41m (feasible); programme-house 24m / 12m (2x surplus). The deficit comes from half the plot perimeter being marked 'private' in harbor/maple -- area_outside skips private/fortified edges. This PREDICTS the corpus fail-count plateau: the two programmes that are frontage-short are exactly the two that plateau (harbor 30-40, maple 74-84 fails), and the two with surplus are the two that effectively solve (programme-house reached 1 fail in a 12k-eval run here). Causal check: relabelling harbor's two private edges as open (identical geometry and programme, perimeter labels only) cut zero-exposure leaves 52%-\u003e19% and seeder crinkliness fails 16.5-\u003e12.0 over 6 seeds.","design":"Ship the bound as a pre-flight check (a 'homemaker-programme-check' style report, or a warning from evolve.py at startup): given a plot and programme, report required vs available frontage and the courtyard area needed to close the gap. This is the cheap, no-ground-truth-needed version of what 2g7.2 objective calibration wanted -- it answers 'is this programme even satisfiable' without needing traced human plans.","acceptance_criteria":"A tool/check that reports the frontage budget per programme dir; DESIGN.md section with the derivation and the corpus table; the plateau programmes flagged as frontage-infeasible-as-specified.","status":"closed","priority":1,"issue_type":"task","assignee":"Claude","owner":"noreply@anthropic.com","created_at":"2026-08-25T23:14:40Z","created_by":"Claude","updated_at":"2026-08-26T16:20:08Z","started_at":"2026-08-26T16:08:13Z","closed_at":"2026-08-26T16:20:08Z","close_reason":"Shipped as `evolve._preflight`, but the headline claim in this issue's title is\nRETRACTED. See DESIGN.md §39.11 (and the partial retraction inserted at §38.3).\n\nWhat was wrong: the \"2.7x / 2.9x short\" figures were computed for a FULLY BUILT\nplot. None of these programmes ask for a fully built plot. Recomputed against\nthe area each programme actually demands (demand / storeys), harbor-house and\nmaple-court are NOT frontage-infeasible -- they need 49 m2 and 22 m2 of\ncourtyard respectively, against 277 m2 and 424 m2 of spare plot. The bound\nitself (L \u003e= A/(1.6202*h)) is sound; it was applied to the wrong quantity.\n\nWhat survives: exactly one corpus programme is infeasible, and not for daylight\nreasons. health-centre demands 240 m2 of floor on a 183 m2 plot (131%). That is\nvisible in the geometry -- every room lands at 0.60x its declared target, 100%\nof them undersized, uniformly. harbor-house and maple-court hit target almost\nexactly (median area / (target * share) = 1.01x), so the plateau is NOT\nexplained by an unsatisfiable brief and remains unexplained.\n\nShipped:\n - `evolve._preflight(programme_dir)`, run at startup before the run banner.\n Two closed-form checks: (1) does demanded floor area fit the plot,\n (2) is there enough daylit wall for it. Advisory only, never blocks a run.\n Fires on health-centre (both) and harbor-house/maple-court (frontage only);\n silent on programme-house.\n - `experiments/diag_exposure_frontage.py frontage` reports the full budget.\n - DESIGN.md §39.11 with the corrected corpus table; §38.3 marked PARTLY\n RETRACTED and cross-referenced.\n\nBoth the check and the diagnostic measure plot area and frontage through\n`geometry`, not the raw init.dom corners, so they carry the `wall_outer` inset\nand plot rotation, and \"daylit\" means exactly what `Fitness.area_outside` means\nby it (external boundary, perimeter type not private/fortified). An earlier\nhand-rolled version of these figures skipped the inset and was ~1 m / ~14 m2\noptimistic per plot; the numbers in §39.11 are the corrected ones.\n\nAcceptance criteria 1 and 2 met. Criterion 3 (\"plateau programmes flagged as\nfrontage-infeasible-as-specified\") is withdrawn as false, not deferred.\n","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-2g7.4","title":"Exact shape-curve inner loop (Otten/Stockmeyer DP) replacing Nelder-Mead","description":"The classic slicing-floorplan result applied to our exact representation: each leaf's size/width/proportion constraints define a feasible-shape region; these compose bottom-up through the slicing tree as piecewise shape curves, yielding in ONE linear pass (no iteration): (a) whether ANY ratio assignment satisfies all per-leaf shape constraints, and (b) the ratios that realize a chosen point on the root curve. Today the same question costs an 80-eval NM run per child (~all of the 3M-eval budget) and answers it only approximately. Plan: (1) prototype on harbor-house-l0 with a rectangular plot approximation; (2) validate against innerloop.optimise — DP-feasible topologies must score \u003e= NM result when polished, DP-infeasible must never reach 0 shape fails under NM; (3) wire as a PRE-FILTER: prune shape-infeasible children before any native eval, and warm-start NM from DP ratios (or replace NM entirely where the plot is near-rectangular; keep NM as final polish for skew). CAVEATS to model honestly: crinkliness/access/adjacency are NOT in the DP (graph terms, not per-leaf shape) — the DP handles the size/width/proportion family only, which is fine for pruning; equal-offset skew-quad geometry means DP areas are approximate — measure the approximation error on real plots first (harbor plot is a near-rect quad). Expected payoff: 100-1000x cheaper feasibility, turning topology search into enumerate-and-prune and unlocking the racing/MAP-Elites/CP issues. Cf. §34: autodiff failed on wall-clock; this is a different attack — exactness via structure, not gradients.","acceptance_criteria":"on harbor-house-l0: DP verdict agrees with NM-polished shape-fail outcome on \u003e=95% of 200 random topologies; measured speedup \u003e=50x per feasibility decision; approximation error on the skew plot quantified","status":"closed","priority":1,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-08-02T09:15:04Z","created_by":"Bruno Postle","updated_at":"2026-08-02T22:42:15Z","started_at":"2026-08-02T18:39:05Z","closed_at":"2026-08-02T22:42:15Z","close_reason":"Prototype PASS: 99.0% agreement (\u003e=95%), 93.6x speedup (\u003e=50x), approximation error quantified (7.5% bbox overestimate). See DESIGN.md §37.2. Not wired into product this session -- follow-up homemaker-py-6xh filed.","dependencies":[{"issue_id":"homemaker-py-2g7.4","depends_on_id":"homemaker-py-2g7","type":"parent-child","created_at":"2026-08-02T10:15:04Z","created_by":"Bruno Postle","metadata":"{}"}],"comments":[{"id":"019fc645-557c-7351-9349-d693e5eefa2b","issue_id":"homemaker-py-2g7.4","author":"Bruno Postle","text":"Post-close correction (user review): the prototype's rectangular\napproximation used an axis-aligned global bbox for each quad's (w,h) --\ncorrect only by coincidence on harbor-house-l0's near-axis-aligned plot\n(~7.5% area error). A real building's orthogonal walls need not align to\nthe plot's survey/CRS axes; confirmed by rotating the plot 45deg, where\nbbox error jumped to 102%.\n\nFixed: (w,h) now measured from edge lengths (edge0+edge2)/2,\n(edge1+edge3)/2 -- rotation-invariant by construction -- and the\nparent/child composition rule (which dimension sums vs. is shared) is now\nderived EXACTLY from child.rotation parity (verified float-exact\nidentity) instead of the empirical geometric heuristic the closed version\nused (which, tried alone without the parity fix, regressed accuracy\n99.0% -\u003e 95.5%).\n\nRe-validated: 99.0% on harbor-house-l0 unrotated (matches original, 0\nfalse negatives), 100% at 97x speedup on the SAME plot rotated 45deg.\nSee DESIGN.md §37.2 (Correction 1 / Correction 2) for full detail.\nhomemaker-py-6xh (production wiring follow-up) still applies.","created_at":"2026-08-03T06:17:40Z"}],"dependency_count":0,"dependent_count":1,"comment_count":1} {"_type":"issue","id":"homemaker-py-2g7.3","title":"Hard/soft fail tiering: 'solved' = zero hard fails","description":"Lex-by-total-count treats a crinkly wall the same as a missing room, so search polishes shape taxes instead of fixing structure — the 3M-run best still carries 'level 0/1 not connected' and wrong-level fails after 1.7M evals. Split fails into HARD (missing space, wrong/required level, level connectivity, circulation connectivity, stairs, covered-outside) and SOFT (crinkliness, proportion, size, width, edge-too-long) tiers. Outer comparator becomes (-hard, -soft, fitness); 'solved' is defined as zero hard fails. GUARDS: (1) the inner-loop 0.5^n cliff must keep protecting against trading into new fails (§4.5/§4.9 — rerun the 0/9 inner-loop-protection check); (2) rerun the §4.9 outer A/B: the scheme must not reintroduce the scalar pathology; (3) §11.4 warns comparator reshaping alone does not escape topology basins — the claim here is narrower: budget stops being spent on soft fails while hard fails remain, and reporting becomes meaningful. The tier map lives in fitness.py next to the fail emission sites so new fail strings must declare a tier. Can start before the calibration issue lands but final tier assignments should be reviewed against its findings.","acceptance_criteria":"tiered comparator behind a flag with A/B on harbor+maple (3 seeds, 20k evals): hard-fail count at budget strictly better or equal on mean, no §4.9 regression; report shows hard/soft split","notes":"ACCEPTANCE A/B COMPLETE — PASS (2026-08-02, experiments/tier_ab_2g7_3.py,\nharbor-house + maple-court, 3 seeds, budget 20000, leaf_sharing=True,\nn_workers=4, wall ~2h53m):\n\n harbor-house hard mean: flat 11.67 -\u003e tiered 5.33 (soft 29.00 -\u003e 42.33)\n maple-court hard mean: flat 19.33 -\u003e tiered 14.00 (soft 71.33 -\u003e 87.67)\n\nHard-fail mean strictly better on BOTH programmes at fixed budget — the\nrequired acceptance bar. Soft/total rise as expected (budget redirected from\npolishing shape fails to structural ones). Full per-seed log at\nscratch/tier_ab_2g7_3/log.txt (not committed — scratch output, regenerate via\nthe script if needed).\n\nGuards: (1) inner-loop 0.5^n cliff untouched by construction (no diff to\ninnerloop.py or the existing 0.5**len(failures) line) — not re-measured\nempirically, doesn't need to be. (2) tiered key is still lexicographic, not a\nblended scalar, so structurally immune to the §4.8 scalar pathology;\nencoded as tests/test_driver.py::test_use_tiers_prefers_fewer_hard_over_fewer_total_fails.\n\nDESIGN.md §37.1 written up with full table and rationale. Feature lands\ndefault-off (--use-tiers / HOMEMAKER_USE_TIERS / driver.search(use_tiers=)),\nso no existing reproduction changes.\n\nFollow-on (not blocking, filed separately): convergence-SPEED comparison\n(evals to 0 hard fails, tiered vs flat, same budget) — this A/B measured\nfail composition at a fixed budget snapshot, not time-to-solved.","status":"closed","priority":1,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-08-02T09:14:14Z","created_by":"Bruno Postle","updated_at":"2026-08-02T17:51:18Z","started_at":"2026-08-02T09:58:53Z","closed_at":"2026-08-02T17:51:18Z","close_reason":"Acceptance A/B passed on both harbor-house and maple-court (hard-fail mean strictly better under tiering); guards verified; DESIGN.md §37.1 written up.","dependencies":[{"issue_id":"homemaker-py-2g7.3","depends_on_id":"homemaker-py-2g7","type":"parent-child","created_at":"2026-08-02T10:14:14Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} @@ -36,6 +36,7 @@ {"_type":"issue","id":"homemaker-py-1p0","title":"Geometry inner loop: full-objective equal-offset ratio optimiser","description":"DESIGN.md §5.1, §7 Phase 1. Productionise experiments/optimize_fullfitness.py into homemaker: optimise(topology, x0=None) -\u003e (geometry, fitness). DOF = equal-offset division ratios of free branches (solver.free_branches, lowest-storey cut ownership), clipped to [eps, 1-eps]. Objective = full oracle fitness (never a proxy — §4.2 falsified). Must support warm-start x0 (§5.6) and a population/batch evaluation mode so each iteration scores via one batched oracle call (§4.6).","acceptance_criteria":"Reproduces or exceeds §4.5 gains (x1.24–x1.67, no new failures) on 2f45907, candidate-002, c964435; works as a library call on any corpus .dom","status":"closed","priority":1,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:36:58Z","created_by":"Bruno Postle","updated_at":"2026-06-12T08:46:31Z","started_at":"2026-06-12T00:14:19Z","closed_at":"2026-06-12T08:46:31Z","close_reason":"innerloop.optimise() lands: batched CMA-ES sigma ladder (0.05/0.15, IPOP popsize doubling, deterministic seeding) over equal-offset free-branch ratios vs full oracle fitness; warm-start x0 supported. Acceptance vs unprojected originals: x1.65/x1.66/x1.58 against bars x1.24/x1.67/x1.59, no new failures, 46 oracle calls vs NM's 200. Two near-bar results accepted as reproduced-within-noise (1% tol) — draw spread brackets the single-NM-draw bars; approved by Bruno 2026-06-12. Gotchas: equal-offset projection of legacy unequal cuts loses fitness/adds failures (midpoint projection used); pycma seed=0 means clock-seeded.","dependencies":[{"issue_id":"homemaker-py-1p0","depends_on_id":"homemaker-py-av5","type":"blocks","created_at":"2026-06-12T00:39:33Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":3,"comment_count":0} {"_type":"issue","id":"homemaker-py-8cs","title":"Experiment: warm-vs-cold start of inner loop (Lamarckian inheritance)","description":"DESIGN.md §5.6, §4.6. Warm-starting a child topology's inner loop from the parent's optimised ratios is the main lever for cutting per-topology cost (~3 min/topology cold). Apply single topology mutations to optimised corpus designs, re-optimise warm (surviving cuts keep values, new cuts get heuristic defaults) vs cold, compare oracle-call counts to convergence at equal final fitness.","acceptance_criteria":"Speedup factor measured across \u003e=10 mutated topologies; decision recorded (expect order-of-magnitude; if \u003c2x, revisit §4.6 Phase-2 scoping)","notes":"Experiment script committed (experiments/warm_vs_cold.py, 1cc86c8) and machinery validated oracle-free; one mutated child scored through the oracle OK. Waiting on homemaker-py-gp2 reference run to finish, then execute under URB_NO_OCCLUSION=1 (3 parents x 400 evals + 12 children x 2 x 200 evals, ~1.5-2 h oracle time). Default budgets: parent 400, child 200; target = evals to 95% of best final.","status":"closed","priority":1,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-11T23:36:58Z","created_by":"Bruno Postle","updated_at":"2026-06-12T11:44:45Z","closed_at":"2026-06-12T11:44:45Z","close_reason":"Measured (URB_NO_OCCLUSION=1, parent budget 400, child 200, 12 single mutations across 3 designs): cold start reached 95% of warm final in 0/12 cases within budget — speedup unbounded at practical budgets; warm finals beat cold finals x1.2-x4 in 12/12; 6/12 warm starts were within 95% at 1 eval (near-neutral mutations). Decision: Lamarckian warm-starting is MANDATORY in the memetic driver (homemaker-py-b39), not an optimisation; cold starts produce strictly worse geometry at equal budget. Note: 2 undivides were exactly fitness-neutral (same-type merge == Merge_Divided equivalence) — locality datum for homemaker-py-nyb.","dependencies":[{"issue_id":"homemaker-py-8cs","depends_on_id":"homemaker-py-1p0","type":"blocks","created_at":"2026-06-12T00:39:34Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-av5","title":"Batched oracle: score many .dom files per invocation","description":"oracle.py currently scores one .dom per urb-fitness.pl call (~1.65 s/dom). DESIGN.md §4.6: batching amortises Perl startup to ~0.99 s/dom and is required so population/batch optimisers can score a whole generation in one oracle call. Extend oracle.py with a batch API: write N .dom files, one perl invocation, parse N .score/.fails pairs. Keep the single-file path for compatibility.","acceptance_criteria":"Batch of 35 corpus files scores in one perl invocation; per-file results identical to single-file calls; measured s/dom reported","status":"closed","priority":1,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:36:56Z","created_by":"Bruno Postle","updated_at":"2026-06-12T00:14:06Z","started_at":"2026-06-11T23:50:40Z","closed_at":"2026-06-12T00:14:06Z","close_reason":"score_batch() lands in oracle.py; 35-file corpus parity verified single-vs-batch (1e-12 rel fitness, exact fail sets); 0.98 s/dom batched vs 1.27 single, x1.30","dependency_count":0,"dependent_count":1,"comment_count":0} +{"_type":"issue","id":"homemaker-py-9gj","title":"quality_uncrinkliness returns a flat hard 0.0, so the objective cannot rank two equally-buried layouts","description":"Narrowed remnant of homemaker-py-ssz after the owner's daylight ruling (DESIGN.md §38.11). A buried leaf usually IS a defect -- corridors and WCs included -- so scoring it badly is correct. The residual complaint is not that the value is low, it is that it is FLAT: quality_uncrinkliness returns exactly 0.0 for every zero-exposure leaf, and since evaluate_leaf multiplies factors into quality and process_storey accumulates value += quality * rate * area, two layouts that differ only in how badly buried their rooms are score identically.\n\nSo the objective gives the search no gradient to descend in precisely the region it most needs to escape. This is a search-mechanics problem, not a calibration one, and it should be judged on whether it helps the search escape -- NOT on fail counts, which by construction it will not move (the fails are real and should stay).\n\nNote the trap recorded in §38.9: an arm optimised under a modified objective must not be scored under the objective it modifies, and equally must not be scored under its own. For a pure gradient change that emits the same fail set, stock scoring IS valid -- that is the one case where the yardstick is sound.","acceptance_criteria":"A variant that keeps the fail set byte-identical to stock (every currently-failing leaf still fails) but is monotone in how buried a leaf is; A/B at fixed budget on harbor + maple with enough seeds to see past the one-seed variance that made the §38.8 n=3 result undecidable.","status":"open","priority":2,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-28T23:14:04Z","created_by":"Claude","updated_at":"2026-08-28T23:14:04Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-7b7","title":"health-centre demands 131% of its plot: the programme is unsatisfiable as written","description":"`evolve._preflight` (homemaker-py-tdp, DESIGN.md 39.11) reports health-centre demanding 240 m2 of floor per storey on a 183 m2 plot -- 131%. It is 1 storey (n_storeys_required=1, storey_minimum=1), so there is nowhere for the overflow to go.\n\nThe consequence is visible in every evaluated layout: 100% of rooms come out undersized, uniformly, at a median 0.60x their declared target. No search can fix this -- quality_size is being asked for something the plot cannot supply, so the size gaussian is pinned near-zero across the whole design and contributes no useful gradient. Contrast harbor-house and maple-court, where the seeder hits targets at median 1.01x.\n\nThis is a corpus data problem, not an engine problem. Either the plot is too small or the programme's sizes/counts were estimated too generously (the CLAUDE.md note that all corpus targets were 'estimated many years ago and never changed' applies).\n\nOptions, roughly in order of honesty:\n 1. enlarge the plot in examples/health-centre/init.dom to ~1.4x\n 2. scale down size/count in patterns.config until demand fits with headroom\n 3. raise the storey count so the demand spreads over 2 levels\n 4. leave it and treat health-centre as a deliberate over-tight brief, documented as such\n\nWhichever is chosen, note it in DESIGN.md 39.11 so the pre-flight warning is not read as a bug in the check.","acceptance_criteria":"health-centre's demanded area per storey fits its plot with headroom, OR the programme is explicitly documented as a deliberately over-tight brief; `evolve._preflight` no longer reports it as an unexplained anomaly; median room area / (target * share) on a constructed seed is materially above 0.60x.","status":"open","priority":2,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-26T16:20:31Z","created_by":"Claude","updated_at":"2026-08-26T16:20:31Z","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"homemaker-py-3qj","title":"Programmes do not declare bedroom/treatment-room to toilet adjacency, so the Brand adaptability credit is never earned","description":"Established while settling homemaker-py-sel. A toilet adjacent to a sleeping or treatment room is a positive even with no door between them -- Stewart Brand, How Buildings Learn: the building may need it knocked through later, and the adjacency is what makes that possible.\\n\\nThe engine already supports this. fitness._evaluate_full runs graph.check_adjacency against graph_base_pre, the UNFILTERED adjacency graph, so a declared adjacency requirement is satisfied by a neighbouring room regardless of the edges graph.has_circulation later strips for routing. (The stripping is correct on its own terms -- you cannot walk through a bedroom to reach the loo.)\\n\\nBut it is only ever scored where a programme DECLARES it, and only one corpus programme does:\\n programme-house (+ derivatives) t1 -\u003e adjacency: [b1] DECLARED\\n harbor-house t (Bathroom, count 6) vs r / n (sleeping) not declared\\n maple-court t, tt vs r / n not declared\\n health-centre t9 / t10 vs tr1 (Treatment Room) not declared\\n\\nSo three of the four real programmes leave the adaptability credit on the table: the search has no reason to place a WC next to a dormitory or a treatment room, because nothing scores it.\\n\\nThis is programme authoring, not an engine change, and it is independent of the usage-key work -- it can land before or after.","acceptance_criteria":"harbor-house, maple-court and health-centre declare the sleeping/treatment-to-toilet adjacencies their briefs imply; re-baselined so the change in fail counts is attributed rather than absorbed.","status":"open","priority":2,"issue_type":"task","owner":"noreply@anthropic.com","created_at":"2026-08-26T12:33:39Z","created_by":"Claude","updated_at":"2026-08-26T12:33:39Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-fdp","title":"constructive_topology is not bit-reproducible on the assign_solver=cpsat path","description":"Established while fixing §39.5. Narrowed but not closed:\\n\\n- cpsat.solve_room_labels IS now reproducible on every captured instance, after two fixes: sorting the model-build order (neighbors[slot] is a set of dom.Node, which hashes by id() -- a memory address -- so raw iteration made the model order vary and CP-SAT returned a different equally-optimal assignment each run), and adding max_deterministic_time alongside the wall-clock cap.\\n- operators.constructive_topology(assign_solver='greedy') IS reproducible.\\n- operators.constructive_topology(assign_solver='cpsat') is NOT: identical seed in the same process gives different leaf-type signatures across runs.\\n\\nSo something upstream of the solver in _assign_adjacency_aware still varies on the cpsat branch. Disabling _cpsat_relabel_settled does not fix it, so it is the first call site. Suspect another id()-hashed set of Nodes feeding slot/neighbour ordering.\\n\\nPlausible contributor to homemaker-py-b8g (parallel/BLAS non-determinism in n_workers\u003e1 runs) -- same id-keying hazard class as the documented geometry._cache issue. Meanwhile tests/test_operators.py::test_assign_cpsat_matches_or_beats_greedy_secondary_adjacency averages three repeats instead of asserting on one run.","acceptance_criteria":"constructive_topology(assign_solver='cpsat') produces identical output for identical seeds in-process and across processes; the A/B test can go back to a single-run assertion.","status":"open","priority":2,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-26T10:06:55Z","created_by":"Claude","updated_at":"2026-08-26T10:06:55Z","dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/DESIGN.md b/DESIGN.md index 9dc05bf..ffae8bb 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -5156,8 +5156,9 @@ sits in? | maple-court | 46 | 13 (28%) | **33 (72%)** | | health-centre | 18 | 9 (50%) | 9 (50%) | -**Roughly two thirds of the zero-value leaves are spaces that architecturally -do not want a window at all** — a broom cupboard, a WC, a plant room, an +**RETRACTED, see §38.11 — the real share is under a tenth.** As written this +claimed that roughly two thirds of the zero-value leaves are spaces that +architecturally do not want a window at all — a broom cupboard, a WC, a plant room, an internal corridor, a covered courtyard. The objective scores them identically with a windowless bedroom. That is the miscalibration, and it is not a gradient problem to be patched with an epsilon; it is the wrong requirement applied to @@ -5255,8 +5256,14 @@ leaf's declared usage: | maple-court `generated.dom` (evolved) | 67 | 43 (64%) | | **overall** | **271** | **164 (61%)** | -**61% of the crinkliness failures the objective reports are not defects**, and -it holds on evolved artefacts, not just seeds. Under +**RETRACTED — the true figure is 9%, see §38.11.** The table above classifies a +fail as a non-defect using `usage:`, exempting corridors, WCs, laundries and +reception; the owner exempts none of those. Only rooms not occupied from day to +day — a cupboard, a store, a plant room — do without daylight. The paragraph as +written said: + +> **61% of the crinkliness failures the objective reports are not defects**, and +> it holds on evolved artefacts, not just seeds. Under `value *= 0.5 ** len(failures)` every one of them halves the fitness of a design that has done nothing wrong — a design is punished for putting the store in the middle of the plan, which is what a competent architect does. That is a @@ -5334,8 +5341,8 @@ programme-house has no utility spaces). | | crinkliness fails | not defects | |---|---|---| -| before | 271 | 136 (50%) | -| after the utility declarations | **243** | 108 (44%) | +| before | 271 | ~~136 (50%)~~ **24 (9%)** — see §38.11 | +| after the declarations | **247** | **0** | The 28 that went are exactly the utility fails. What remains is two populations the corpus cannot reach, because neither is a `spaces:` entry: @@ -5354,6 +5361,79 @@ settable to `none` like any space (tested), but the default is deliberately on, and this is 63% of the remaining phantom fails, so it is not a call to make by inference. +### 38.11 Owner's ruling on daylight, and the retraction of §38.8's headline + +**Ruling: corridors need daylight. Only rooms that are not occupied from day to +day — a cupboard, a store, a plant room — do without it.** + +That overturns the classification §38.8 and §38.9 were built on, and with it +their headline number. Those sections exempted, on my inference rather than any +ruling: internal circulation, covered courtyards, WCs and bathrooms, laundries, +and reception/waiting/foyer. **None of those are exempt.** A corridor is +occupied all day, every day; so is a waiting room; a laundry is a room people +spend time in; a sterilisation room is a workplace. + +Re-measured against the ruling, with the classification read from the corpus +(a space is exempt exactly when its own `patterns.config` declares +`crinkliness: none`) rather than inferred: + +| layout | crinkliness fails | not defects | +|---|---|---| +| harbor-house, 3 constructed seeds | 67 | 8 (12%) | +| maple-court, 3 constructed seeds | 112 | 9 (8%) | +| health-centre, 3 constructed seeds | 20 | 2 (10%) | +| harbor-house `generated.dom` (evolved) | 5 | 1 (20%) | +| maple-court `generated.dom` (evolved) | 67 | 4 (6%) | +| **overall** | **271** | **24 (9%)** | + +**9%, not 61%.** The objective's daylight requirement was mildly miscalibrated, +not massively so, and I overstated it by a factor of about six by inventing a +classification instead of asking for one. + +**`uncrinkliness_circulation` is therefore left at `[5/6, 1.1/3]`.** §38.10 +called its equality with the habitable target "the purest case of a value never +tuned". It is not a bug: corridors want daylight on the same terms as rooms, so +the two targets agreeing is the correct answer, arrived at by default. The key +stays available for a programme that wants to differ. + +**The corpus declarations are narrowed to match.** `usage: utility` was too +coarse a proxy — it swept in Laundry Rooms and a Sterilisation Room, all of +which are occupied. 14 spaces now declare `crinkliness: none`, and every one is +genuinely unoccupied: + +| programme | declared `crinkliness: none` | +|---|---| +| harbor-house | Ground/First Floor Storage, Mechanical/Electrical Room, Utilities Closet | +| harbor-house-l0 | Ground Floor Storage, Mechanical/Electrical Room | +| health-centre | General Storage, Plant / Mechanical Room, Records Room | +| maple-court | Ground/First/Second Floor Storage, Mechanical/Electrical Room, Utilities Closet | + +*(Records Room is the one debatable entry — a store you fetch a file from, not a +desk. Flip it to a declared target if it is meant to be worked in.)* + +**What survives §38.8/§38.9 unchanged**, because none of it depended on the +classification: + +- the §38.6 critique. `floor` returns 0.01 for a buried leaf, `compact_ok` + contradicted itself, and `exempt_circulation` reached a third at most. Those + are facts about the code, and they are why §38.6 measured a null; +- `usage_daylight` was mis-keyed. §38.9's reasoning for that was right even + though its numbers were not — `usage:` is an access axis; +- the §38.8 A/B's yardstick was wrong: scoring the repair under the objective + it repairs penalises it for repairing; +- the mechanism. Crinkliness was the only leaf quality factor with no per-space + target, and §38.10's fix stands on the owner's design, not on my numbers. + +**What this does to `ssz` as a whole.** The issue opened on "45–56% of interior +leaves are zero-exposure and score a hard zero, so the objective assigns no +value to any interior room". That measurement was right, but the reading was +wrong: under this ruling **a buried leaf usually IS a defect**, corridors and +WCs included, so scoring it zero is largely *correct*. What remains of the +complaint is narrower and is about search mechanics rather than truth — a hard +`0.0` cannot rank two bad layouts against each other, so the objective is +flat where it should be merely low. That is worth a separate issue; it is not +the calibration fault this section spent its length chasing. + ## 39. Config audit: requirements that actively fight the engine (`homemaker-py-ju3`) — measured 2026-08-25 The corpus `patterns.config` targets and `costs.config` values were estimated diff --git a/examples/harbor-house-l0/patterns.config b/examples/harbor-house-l0/patterns.config index b515e24..9d0f476 100644 --- a/examples/harbor-house-l0/patterns.config +++ b/examples/harbor-house-l0/patterns.config @@ -98,7 +98,6 @@ spaces: count: 3 la1: - crinkliness: none # no window needed usage: utility name: Laundry Room size: diff --git a/examples/harbor-house/patterns.config b/examples/harbor-house/patterns.config index d98839f..d915d7a 100644 --- a/examples/harbor-house/patterns.config +++ b/examples/harbor-house/patterns.config @@ -141,7 +141,6 @@ spaces: count: 6 # 3 ground + 3 first floor la1: - crinkliness: none # no window needed usage: utility name: Laundry Room size: diff --git a/examples/health-centre/patterns.config b/examples/health-centre/patterns.config index eb958f5..59afba4 100644 --- a/examples/health-centre/patterns.config +++ b/examples/health-centre/patterns.config @@ -130,7 +130,6 @@ spaces: - ms1 zt1: - crinkliness: none # no window needed usage: utility name: Sterilisation Room size: diff --git a/examples/maple-court/patterns.config b/examples/maple-court/patterns.config index fdb48e1..a5ce745 100644 --- a/examples/maple-court/patterns.config +++ b/examples/maple-court/patterns.config @@ -94,7 +94,6 @@ spaces: - o la1: - crinkliness: none # no window needed usage: utility name: Laundry Room size: diff --git a/experiments/audit_crinkliness_truth.py b/experiments/audit_crinkliness_truth.py index 8462fc7..0995497 100644 --- a/experiments/audit_crinkliness_truth.py +++ b/experiments/audit_crinkliness_truth.py @@ -1,17 +1,20 @@ """Are the crinkliness failures the objective emits real defects? (`homemaker-py-ssz`) Not an A/B. This asks a correctness question the search cannot answer: of the -`crinkliness` failures the STOCK objective reports, how many are on a space -that architecturally wants daylight at all? +`crinkliness` failures the GLOBAL-target objective reports -- one daylight +requirement for every space, which is what the engine did before §38.10 -- how +many are on a space that does not want daylight at all? A `crinkliness` fail says "this leaf has too little exposed wall for its area". -For a bedroom or a living room that is a real defect. For a broom cupboard, a -WC, a plant room, an internal corridor or a covered courtyard it is not -- those -are ordinary buried architecture, and the fail is an artefact of applying one -daylight requirement to every space regardless of use (DESIGN.md §38.8). +For anything occupied day to day that is a real defect. For a cupboard, a store +or a plant room it is not. -Every fail is classified by the leaf's DECLARED `usage:` (§39.7), so nothing -here rests on how a code is spelled. +**The classification is read from the corpus, not guessed here.** A fail counts +as a non-defect exactly when that space declares `crinkliness: none` in its own +`patterns.config`. An earlier version of this script inferred it from `usage:` +instead and got a much larger, wrong answer -- it exempted corridors, WCs, +laundries and reception, none of which the owner exempts (DESIGN.md §38.11). +Corridors, courtyards and every occupied room want daylight. Usage:: @@ -36,12 +39,11 @@ from homemaker_layout import operators, programme CORPUS = ["examples/harbor-house", "examples/maple-court", "examples/health-centre"] -# Ruled by the project owner: everything a person occupies wants a window -- -# WCs and bathrooms included, reception/waiting/foyer included, offices and -# consulting rooms included. Only stores, plant, records and laundry do not, -# together with the generic structural types (a corridor has its own -# `uncrinkliness_circulation` target; a courtyard is not a room). -NO_DAYLIGHT = {"utility"} +# Ruled by the project owner: only rooms that are not occupied from day to day +# -- a cupboard, a store, a plant room -- do without daylight. Corridors need +# it. So does everything else: WCs, laundries, reception, waiting rooms, +# offices, consulting rooms. Which spaces those are is read from the configs +# themselves (a declared `crinkliness: none`), never inferred here. def stock_fitness(progdir: str) -> fitness.Fitness: @@ -64,7 +66,12 @@ def constructed(progdir: str, s: int) -> dom_mod.Node: def audit(fit: fitness.Fitness, root: dom_mod.Node) -> collections.Counter: - """usage -> count, over the leaves that emit a stock `crinkliness` fail.""" + """label -> count over the leaves that fail under ONE GLOBAL daylight target. + + Each is labelled with the leaf's usage, and marked exempt when that space + declares `crinkliness: none` -- i.e. when the failure the old objective + emitted was not a defect. + """ tree = copy.deepcopy(root) geometry.clear_cache() dom_mod.canonicalize_shares(tree) @@ -79,25 +86,33 @@ def audit(fit: fitness.Fitness, root: dom_mod.Node) -> collections.Counter: for leaf in lvl.leaves(): if dom_mod.is_outside(leaf) and not dom_mod.is_covered(leaf): continue - if fit.quality_uncrinkliness(leaf, graphs[li], groups) >= fitness.FAIL_THRESHOLD: - continue # not a failure - out[fit.usage_of(leaf) or f""] += 1 + # the PRE-§38.10 objective: one global target for every leaf + crink = fit.crinkliness(leaf, graphs[li], groups) + if crink: + distance, sigma = fit.conf("uncrinkliness") + q = fitness.gaussian(1 / crink, 1.0, distance, sigma) + else: + q = 0.0 + if q >= fitness.FAIL_THRESHOLD: + continue # not a failure even then + label = fit.usage_of(leaf) or f"" + if fit.crinkliness_params(leaf) is None: + label += " [declares crinkliness: none]" + out[label] += 1 return out def report(label: str, tally: collections.Counter) -> tuple[int, int]: total = sum(tally.values()) - real = sum(n for u, n in tally.items() if u not in NO_DAYLIGHT - and not u.startswith("4} {verdict}") + verdict = ("not a defect -- not occupied day to day" + if "crinkliness: none" in usage else "REAL DEFECT") + print(f" {usage:<44}{n:>4} {verdict}") print(f" -> {total - real}/{total} ({100 * (total - real) / total:.0f}%) " f"are reported against spaces that do not want daylight\n") return real, total