homemaker-layout/.beads/issues.jsonl

54 lines
76 KiB
Text
Raw Normal View History

{"id":"homemaker-py-c4c.3","title":"Staged per-floor search (curriculum: credible base floor, then upper floors as deltas)","description":"Search the genome in its causal dependency order. The base-floor tree is the master; upper storeys are deltas (Below-inheritance). The programme partitions rooms by required level (harbor: 10 L0, 4 L1, 2 free), so each floor's target room set is known up front. Today the search discovers both floors simultaneously via random typing + the rare/drastic level_add (weighted 0.2) — an uncontrolled, degenerate version of staging.\nStage 1 — base floor: search the single-storey tree over the level-0 room set, dimensionality reduced (one tree, no deltas).\nStage 2 — upper floors as deltas: seed each upper storey with ITS required room set (via the construction op, homemaker-py-c4c.2), search the deltas; keep the base MUTABLE at low probability so it can adapt to upper-floor pressure.\nCRITICAL non-goal: do NOT hard-freeze the base. A base optimised purely as ground floor is a §4.2-style partial objective and can be a bad SUBSTRATE. Stage 1 objective must include (a) a reserved, vertically-alignable circulation core and (b) a substrate-readiness term: enough divisible area/cut structure to host the level-1 room set later.","design":"Premise gated by homemaker-py-c4c.1: only high-value if single-storey construction already reaches low fails. Substrate-readiness proxy candidates: count of base leaves large enough to subdivide for L1 rooms; presence of a core node with vertical continuity. Stage transition: when stage-1 base hits a fails/score threshold or budget fraction, freeze-soft and open the delta genome. Composes with canonical encoding (homemaker-py-9gp) — deltas are where redundancy/coarse moves hurt most.","acceptance_criteria":"Staged search beats single-stage on harbor-house (best fails/score), measured at equal native-fitness budget and recorded in DESIGN.md §11.x + bead notes. Reserved-core + substrate-readiness shown to prevent the bungalow trap (stage-2 does not have to carve a core from scratch — track core-carving moves). No regression on programme-house.","notes":"DONE. Implemented driver.search_staged (Stage 1 single-storey base over level-0 set with substrate-readiness ranking bonus; Stage 2 upper floors lifted as constructed deltas, base mutable at base_p=0.15). New: programme.{n_storeys_required,partition_rooms_by_storey,write_stage1_programme}, graph.substrate_readiness, operators.{lift_base_to_storeys,_pick_weighted_by_storey,base_p}, driver.search rank_bonus_fn/seed_factory/base_p hooks, experiments/run_staged_search.py, tests/test_staging.py. RESULT (harbor, 20000 evals, seed 0): staged 95 fails vs single-stage 105 (-10, -9.5%); gain in crinkliness 27-\u003e18 + edge 12-\u003e8, small access cost +5. Anti-bungalow CONFIRMED: all Stage-2 core_divide/undivide in winning lineage are noops (core inherited, not carved). Regression PASS: programme-house warmstart-2f4 still reaches whole-pop 1-fail. DESIGN.md §11.3 filled. Remaining high-fail plateau is §11.4 (graded objective) territory.","status":"closed","priority":1,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-17T19:01:01Z","created_by":"Bruno Postle","updated_at":"2026-06-18T05:04:48Z","started_at":"2026-06-18T04:25:07Z","closed_at":"2026-06-18T05:04:48Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-c4c.3","depends_on_id":"homemaker-py-c4c","type":"parent-child","created_at":"2026-06-17T20:01:00Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-c4c.3","depends_on_id":"homemaker-py-c4c.1","type":"blocks","created_at":"2026-06-17T20:01:00Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-c4c.3","depends_on_id":"homemaker-py-c4c.2","type":"blocks","created_at":"2026-06-17T20:01:01Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-c4c.2","title":"Programme-aware construction + missing-room repair operator","description":"Highest-leverage fix for the epic's diagnosis. Today mutate_divide (operators.py:71) types new leaves at RANDOM, so required programme spaces go missing -\u003e 'missing' stacking dominates fitness on full programmes (harbor: 6 missing-room records stacking critical+size+width+adjacency+level). Make the required room set a constructive invariant rather than something the search must stumble onto.\nTwo parts:\n1. Constructive seeder: generate initial topologies that instantiate each required space (respecting count/level/type) by construction, instead of random divide+retype chains.\n2. Repair operator mutate_place_missing: detect a required-but-absent space and insert it (divide a compatible leaf, type the new leaf to the missing code, prefer a slot satisfying its adjacency). Complements mutate_level_compound_fix (which repairs level, not presence).\nWire the seeder into driver bootstrap and the repair op into mutate() weights.","design":"Seeder must place generic C (circulation/core) and O (outside) too, not just programme codes. Keep it stochastic (diverse population) but biased to cover the required set + correct levels. Repair op should be lex-safe: prefer insertions that don't create more new fails than the missing-stack it removes (cf. the §4.10 deceptive-valley lesson — a naive insert dumps a room into a bad slot and nets worse).","acceptance_criteria":"On harbor-house, 'missing'-type failures collapse to ~0 across the population (record before/after fail histograms); measured net-fail improvement vs current 74-fail out1.dom baseline, recorded in DESIGN.md §11.x + bead notes. No regression on seeded programme-house (still reaches 1-fail optimum, §4.10).","notes":"DONE 2026-06-17. Implemented constructive_topology seeder + mutate_place_missing repair op (operators.py), wired into driver bootstrap + mutate weights. A/B on harbor (20k evals, seed 0, identical config): old random-bootstrap 133 fails (103 missing, 77%) -\u003e new constructive 105 fails (12 missing, 11%); missing-records 22-\u003e2; -21% total. Seed head-start 163-\u003e139. §4.10 regression PASS: warmstart-2f4 still reaches 1-fail population at 50k. Verdict: construction necessary, reframes bottleneck to quality-fail packing (crinkliness/size/access/edge) of complete dense design -\u003e unblocks §11.3 staging, motivates §11.4 graded objective. Follow-up filed: adjacency-aware seeding. Full numbers in DESIGN.md §11.2. 186 tests pass.","status":"closed","priority":1,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-17T18:51:21Z","created_by":"Bruno Postle","updated_at":"2026-06-17T21:50:34Z","started_at":"2026-06-17T20:19:39Z","closed_at":"2026-06-17T21:50:34Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-c4c.2","depends_on_id":"homemaker-py-c4c","type":"parent-child","created_at":"2026-06-17T19:51:20Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":3,"comment_count":0}
{"id":"homemaker-py-c4c.1","title":"Experiment: single-storey harbor premise test (per-floor construction vs multi-storey coupling)","description":"De-risk the staged-search and construction work BEFORE building either. Strip harbor-house to its 10 level-0 rooms as a single-storey programme; run the current memetic search from a bare plot; record best fails/score and the fail-type histogram. This isolates the question: is the bottleneck per-floor CONSTRUCTION (placing the right room set on one floor) or the multi-storey COUPLING (deltas, core alignment, level constraints)?\n- If single-storey 10-room reaches near-zero fails: the difficulty is coupling -\u003e staged per-floor search (homemaker-py-\u003cstaging\u003e) is the high-value lever.\n- If it still stalls at many fails (esp. 'missing'): per-floor construction itself is the bottleneck -\u003e programme-aware construction (homemaker-py-\u003cconstruction\u003e) is required first and staging alone won't rescue it.\nRun from blank-slate (init.dom equivalent) AND from a bootstrap population; report both.","design":"Build examples/harbor-house-l0/ from harbor's level-0 spaces only (drop level: keys or set all to 0; keep adjacency among the retained codes). Reuse experiments/run_search_scaled.py harness. Cheap (~minutes at native-fitness throughput).","acceptance_criteria":"Single-storey 10-room harbor variant created and committed under examples/; current search run and best fails/score + fail histogram recorded in DESIGN.md (new §11.x) and bead notes; explicit verdict on construction-vs-coupling.","notes":"VERDICT: per-floor CONSTRUCTION is the bottleneck, not multi-storey coupling.\nBuilt examples/harbor-house-l0/ (10 explicit level:0 codes = 13 room instances, single-storey constraints), seeded from bare init.dom.\nRun: URB_NO_OCCLUSION=1 python3 experiments/run_search_scaled.py examples/harbor-house-l0 20000 0 examples/harbor-house-l0/init.dom examples/harbor-house-l0/generated.dom\nResult: 20000 evals / 250 topologies / 234s. Best 33 fails (fitness 2.25e-12, deep in 0.5^n regime); whole pop stuck 33-35. 40-\u003e33 over full budget. NOT near zero.\nFail histogram: 13 missing (all 3 m meeting rooms never built) + 6 adjacency + 4 access + 4 size + 2 edge-too-long + 2 crinkliness + 1 proportion + 1 too-few-stairs(single-storey artifact). Missing = 39% — matches the 'still stalls esp. missing' branch.\n=\u003e c4c.2 (programme-aware construction + missing-room repair) is the prerequisite; staging (c4c.3) alone won't rescue it. c4c.3 already correctly depends on both. Full writeup in DESIGN.md §11.1.","status":"closed","priority":1,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-17T18:49:43Z","created_by":"Bruno Postle","updated_at":"2026-06-17T20:15:36Z","started_at":"2026-06-17T19:25:49Z","closed_at":"2026-06-17T20:15:36Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-c4c.1","depends_on_id":"homemaker-py-c4c","type":"parent-child","created_at":"2026-06-17T19:49:43Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":1,"comment_count":0}
{"id":"homemaker-py-c4c","title":"Phase 6: topology-search quality for full/multi-storey programmes","description":"Diagnosis (survey 2026-06-17): the delivered speedups (native fitness ~140x, geometry inner loop ~1.6x) landed in the two layers that were never the bottleneck. The geometry inner loop polishes WITHIN a failure tier (DESIGN.md §4.5/§4.7: 0 fail changes, by design — the 0.5^n cliff protects it). But final design quality is dominated by FAILURE COUNT, which is almost entirely a topology property. Topology search on full programmes is the weakness:\n- blank-slate programme-house (init.dom): memetic stalls at 18 fails vs urb-evolve 6 (§7 Phase 2 verdict);\n- harbor-house (16 rooms): out1.dom=74 fails, generated.dom=130 fails, both at ~machine-epsilon score; fails dominated by 'missing' room stacking (each missing room stacks critical+size+width+adjacency+level, §6).\nSmoking gun: operators.mutate_divide (operators.py:71) assigns each new leaf a RANDOM type from programme-codes+C+O. Nothing guarantees the required programme spaces are instantiated, so on a large programme required rooms go missing -\u003e catastrophic 0.5^n stacking, and the search is a random walk over type assignments with a flat/catastrophic gradient in the high-fail regime.\nThis epic groups the topology-search-quality work: programme-aware construction, staged per-floor search, graded high-fail objective, topology diversity, then the canonical-encoding capstone. Everything experiment-driven; results recorded in DESIGN.md sections + bead notes.","design":"Causal frame: base-floor tree is the master genome; upper storeys are divide/undivide deltas (Below-inheritance); the programme partitions rooms by required level (harbor: 10 on L0, 4 on L1, 2 free). So construction and search should follow the genome's dependency order: credible base floor first, upper floors as deltas, with required-room sets known per floor from the programme. Do NOT hard-freeze the base when adding floors — that recreates the §4.2 partial-objective trap at the topology level (a base optimised purely as ground floor can be a bad SUBSTRATE: vertical core must stay aligned, load-bearing walls must stack). Curriculum, not freeze.","acceptance_criteria":"Memetic search reaches a competitive low-fail design on harbor-house (16 rooms, multi-storey) and on blank-slate programme-house, beating the current 74/18-fail plateaus; each child bead lands its experiment with results recorded in DESIGN.md.","status":"open","priority":1,"issue_type":"epic","owner":"bruno@postle.net","created_at":"2026-06-17T18:45:39Z","created_by":"Bruno Postle","updated_at":"2026-06-17T18:45:39Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-mz5","title":"Python native fitness evaluation (port urb-fitness.pl)","description":"We need a Python implementation of the urb-fitness scoring tool that is faithful to the Perl oracle (urb-fitness.pl / ProgrammeDriven.pm). This is the 'native fitness' component identified in DESIGN.md §6 as gating topology search at scale — the oracle requires a subprocess+file roundtrip per eval which is too slow for large populations.\n\nThe native fitness must reproduce all scoring terms from the Perl source:\n- size, width, proportion (per-space Gaussian scoring)\n- adjacency, access/inaccessible, crinkliness, perpendicular\n- level, staircase volume/count, public access\n- circulation \u0026 outside ratios, min internal area\n\nSource of truth: /home/bruno/src/urb/lib/Urb/Dom/Fitness/ProgrammeDriven.pm and the Storey/Building/Leaf/Base submodules.\n\nValidation target: match oracle scores on the programme-house corpus (35+ .dom files) to within the ~3.7% gap documented in homemaker-py-gpx.","status":"closed","priority":1,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-15T22:18:06Z","created_by":"Bruno Postle","updated_at":"2026-06-17T17:51:53Z","closed_at":"2026-06-17T17:51:53Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-40i","title":"Investigate cf0b8a77e8b2325f ~18% raw_value discrepancy (py lower than oracle)","description":"For prefix cf0b8a77e8b2325f: oracle=1.079112e-03 py=9.133243e-04 ratio=0.8464 (python is ~18% too low). debug_nfails shows py n_fails=5 oracle n_fails=5 (same failures), stair_fits=[1.3145] in python, building_factor=0.1104 (vs oracle's implied ~0.1303). The discrepancy is in raw_value (py=11837 vs oracle implied ~13975) or possibly building_factor. Need to check: (1) per-leaf quality values (crinkliness, area_outside, access) via debug_quality.txt; (2) whether the stair corners differ (cf/rl: py=[2,3] perl=[2,3] — SAME, so corners ok); (3) any quality term not yet ported or computed differently. Run debug_quality.py and compare per-leaf contributions.","status":"closed","priority":1,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-13T18:08:22Z","created_by":"Bruno Postle","updated_at":"2026-06-13T19:54:04Z","started_at":"2026-06-13T18:12:23Z","closed_at":"2026-06-13T19:54:04Z","close_reason":"Investigation complete: traced 18% discrepancy (cf0b8a77) through entrance corner logic and weighted path length bugs, both now fixed in w1e.","dependencies":[{"issue_id":"homemaker-py-40i","depends_on_id":"homemaker-py-hgg","type":"blocks","created_at":"2026-06-13T19:08:30Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
{"id":"homemaker-py-w1e","title":"Port Perl entrance-corner logic into Python stair-fit (ca/cb parity)","description":"Perl's check_stair_fit (Leaf.pm:104-142) adds entrance edge corners to corners_in_use before computing stair_fit. Python's process_storey does not. For ca9e80c5c1502f10 and cb93a2d2de7f5d37 the oracle stair leaf 'lr' has corners [1,2,3] (from perl_bf.pl) but debug_corners.py Perl-compatible trace gives [2,3] — the extra corner 1 comes from Entrances(graph)-\u003eBoundary_Id logic. Need to: (1) port dom.Entrances() — returns {leaf_id: boundary_id} for the best-entrance leaf at ground level (Entrances() returns {} if level\u003e0); (2) port leaf.Boundary_Id(side) — returns the node sharing that edge; (3) in fitness.process_storey, after stack_corners_in_use, add entrance-edge corners before computing stair_fit. Acceptance: ca/cb ratio ≈ 1.0 (currently 1.33).","status":"closed","priority":1,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-13T18:08:11Z","created_by":"Bruno Postle","updated_at":"2026-06-13T19:53:40Z","started_at":"2026-06-13T19:09:35Z","closed_at":"2026-06-13T19:53:40Z","close_reason":"Fixed: entrance corner logic via _entrance_bid_for_stair (mirrors Perl Entrances), plus root cause: _avg_path_len_from now uses weighted Dijkstra (centroid distances) matching Perl graph.average_path_length — fixes has_circulation edge removal order. All 4 debug prefixes ratio=1.000, 39 tests pass.","dependencies":[{"issue_id":"homemaker-py-w1e","depends_on_id":"homemaker-py-hgg","type":"blocks","created_at":"2026-06-13T19:08:29Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
{"id":"homemaker-py-q70","title":"Fix corners_in_use _ib(None,None) bug: triple-at-idx=3 always passes in Perl","description":"In graph.py corners_in_use(), the _ib helper returns False when pa=None or pb=None. Perl's is_between_2d(point, undef, undef) returns True (distance_2d(undef,x)=0 so abs(0-0-0)\u003c1e-6). At triple-check idx=3, c1=corners[4]=None and c2=None, so _ib(w, None, None) must return True to match Perl — meaning the triple always succeeds at idx=3. Fix: add 'if pa is None and pb is None: return True' before the existing 'if pa is None or pb is None: return False'. This is already applied to graph.py. Needs: run 35-file corpus parity test to confirm aa0dcab98927d2c9 passes (corners [0,1,3] → stair_fit=0.878 → sf_factor≈0.570 ≈ oracle).","status":"closed","priority":1,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-06-13T18:07:54Z","created_by":"Bruno Postle","updated_at":"2026-06-13T19:53:53Z","closed_at":"2026-06-13T19:53:53Z","close_reason":"Fixed as part of homemaker-py-w1e: the _avg_path_len_from weighted Dijkstra fix corrects has_circulation edge removal ordering, which was the actual cause of wrong stack corner counts. The _ib(None,None)=True fix was already in place but the weighted path length was the remaining blocker.","dependencies":[{"issue_id":"homemaker-py-q70","depends_on_id":"homemaker-py-hgg","type":"blocks","created_at":"2026-06-13T19:08:28Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
{"id":"homemaker-py-gp2","title":"Disable occlusion/daylight in Urb oracle (env flag); re-baseline scores","description":"Strategy decision (Bruno, 2026-06-12): occlusion/daylight is orthogonal to whether a better, scalable optimisation system can be built — disable it in Urb rather than port it. Patch Urb behind an env flag (e.g. URB_NO_OCCLUSION=1): quality_daylight returns 1 for outdoor spaces too, and Crinkliness/Area_Outside pins the CIEsky_vertical illumination factor to 1 (simple crinkliness = unweighted external wall area / floor area). Keep the occlusion object plumbing — it carries the Walls/boundaries cache crinkliness needs (ProgrammeDriven.pm:97). Then re-baseline everything once at this clean boundary: corpus .score files, the DESIGN.md $4.5 gains table, accept_innerloop.py gate bars. Also measure oracle s/dom with the flag on — occlusion sampling may be a real slice of the ~1 s/dom cost. The native Python fitness then ships with simple crinkliness only; full occlusion rebuild is deferred post-Phase-5 (homemaker-py-2g5).","acceptance_criteria":"Env-flagged Urb patch; flag on: corpus re-scored, gate bars re-derived, oracle s/dom re-measured; urb-evolve confirmed to respect the flag for the Phase-2 benchmark","status":"closed","priority":1,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-12T07:27:30Z","created_by":"Bruno Postle","updated_at":"2026-06-12T09:31:40Z","closed_at":"2026-06-12T09:31:40Z","close_reason":"URB_NO_OCCLUSION=1 patch in Urb (Leaf.pm quality_daylight -\u003e 1, Dom.pm Area_Outside illumination pinned; flag-off byte-identical, verified). Corpus re-baselined: 35/35 scores shift, one expected crinkliness failure-set change, 0.92 s/dom batched (x1.08). New reference gains recorded in DESIGN §4.7 and accept_innerloop bars (x1.63/x1.70/x1.68, deterministic seed). urb-evolve respects flag by construction. NOTE: Urb working-tree changes left uncommitted in /home/bruno/src/urb for Bruno's review.","dependency_count":0,"dependent_count":3,"comment_count":0}
2026-06-13 21:47:40 +01:00
{"id":"homemaker-py-uxz","title":"Native fitness validation: 35-file corpus parity vs oracle; retire oracle (Phase 3 gate)","description":"DESIGN.md §7 Phase 3 gate. Validate the assembled native fitness against urb-fitness.pl across all 35 programme-house .dom files: scores within float tolerance AND identical failure sets. Swap behind the same interface as oracle.score so inner loop and search driver are unchanged; keep the oracle available as validation reference but stop using it in search. Then re-run topology search at scale (separate issue).","acceptance_criteria":"35/35 files: score parity within tolerance, failure sets identical; search runs end-to-end on native fitness with measured speedup vs oracle","status":"closed","priority":1,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:38:27Z","created_by":"Bruno Postle","updated_at":"2026-06-13T20:45:30Z","started_at":"2026-06-13T19:57:48Z","closed_at":"2026-06-13T20:45:30Z","close_reason":"35/35 score parity + fail-set parity; NativeEvaluator added; optimise() defaults to use_native=True; 23x speedup; one bug fix (_entrance_bid_for_stair via-outdoor case)","dependencies":[{"issue_id":"homemaker-py-uxz","depends_on_id":"homemaker-py-3y7","type":"blocks","created_at":"2026-06-12T00:39:40Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-uxz","depends_on_id":"homemaker-py-40i","type":"blocks","created_at":"2026-06-13T19:08:33Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-uxz","depends_on_id":"homemaker-py-gnw","type":"blocks","created_at":"2026-06-12T00:39:41Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-uxz","depends_on_id":"homemaker-py-gp2","type":"blocks","created_at":"2026-06-12T08:27:44Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-uxz","depends_on_id":"homemaker-py-hgg","type":"blocks","created_at":"2026-06-12T00:39:43Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-uxz","depends_on_id":"homemaker-py-q70","type":"blocks","created_at":"2026-06-13T19:08:31Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-uxz","depends_on_id":"homemaker-py-w1e","type":"blocks","created_at":"2026-06-13T19:08:32Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":7,"dependent_count":3,"comment_count":0}
{"id":"homemaker-py-hgg","title":"Native fitness: storey/building checks + missing-space failure stacking","description":"DESIGN.md §6. Port ProgrammeDriven/Storey/Building checks: space-count matching with MISSING-SPACE FAILURE STACKING (2 base failures + 1 per size/width/proportion/adjacency/level requirement, up to ~7 — ProgrammeDriven.pm:192-212; reshaping must preserve this hierarchy), adjacency/level/requires_below checks, staircase fit/volume/min-max, public access, circulation \u0026 outside ratios, min internal area (1.2x programme sum), storey limit/minimum, structural failures (edge too long \u003e8 m both variants, unsupported covered outside, covered outside above ground, level not connected, inaccessible usable space), preprocess_building s-\u003eO conversion, and the 0.5^n penalty over value/cost.","acceptance_criteria":"Failure sets and final scores match the oracle on sample files; failure-stacking counts identical","status":"closed","priority":1,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:38:26Z","created_by":"Bruno Postle","updated_at":"2026-06-13T18:11:27Z","started_at":"2026-06-13T08:59:14Z","closed_at":"2026-06-13T18:11:27Z","close_reason":"Implementation complete: storey/building checks, failure stacking, staircase logic, public access, circulation ratios, structural checks all ported. 39 tests pass.","dependency_count":0,"dependent_count":4,"comment_count":0}
{"id":"homemaker-py-gnw","title":"Native fitness: leaf quality terms + cost model","description":"DESIGN.md §6. Port Leaf.pm quality terms (size, width, proportion, perpendicular, access) with programme-driven parameter lookup (get_space_params fallback chain, generic c/o/s handling, width_inside [4.0,1.0] default), gaussian scoring, FAIL_THRESHOLD=0.1. Also the COST DENOMINATOR — fitness is value/cost: per-leaf area costs, interior/exterior wall edge costs, boundary costs, value rates (Leaf.pm:194-251, Storey.pm:122-147). Cost couples to geometry too.","acceptance_criteria":"Per-leaf quality factors and per-storey cost/value match Perl (float tolerance) on sample corpus files with DEBUG output diffed","notes":"Crinkliness scope (2026-06-12): port SIMPLE crinkliness only — external wall area / floor area with the CIEsky illumination factor pinned to 1 (boundary-overlap geometry from Dom-\u003eWalls stays in scope; the sky model does not). Must match the URB_NO_OCCLUSION-flagged oracle (homemaker-py-gp2), not stock Urb. quality_daylight = 1 for all spaces.","status":"closed","priority":1,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:38:24Z","created_by":"Bruno Postle","updated_at":"2026-06-13T07:00:07Z","started_at":"2026-06-12T21:07:06Z","closed_at":"2026-06-13T07:00:07Z","close_reason":"0-mismatch parity: 35 files, 407 leaves, 2849 factors","dependencies":[{"issue_id":"homemaker-py-gnw","depends_on_id":"homemaker-py-gp2","type":"blocks","created_at":"2026-06-12T08:27:46Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
{"id":"homemaker-py-3y7","title":"Native fitness: adjacency/connectivity graph build + Merge_Divided semantics","description":"DESIGN.md §6 port scope, §7 Phase 3 (native fitness gates topology search at scale — §4.6). Port the door_width (1.2 m) adjacency graph (Urb Dom Graph), Merge_Divided, and the TWO-PHASE build: adjacency/level/vertical checks run on the UNMERGED tree, graphs rebuilt after Merge_Divided for storey processing (ProgrammeDriven.pm:83-103). Port faithfully — including has_vertical_connection's no-spatial-overlap stub (ProgrammeDriven.pm:399-423) unless the fidelity decision (§8.1) says otherwise; record the decision.","acceptance_criteria":"Graph edges/widths and merged structure match Perl on the 35-file corpus; vertical-connectivity fidelity decision recorded","status":"closed","priority":1,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:38:23Z","created_by":"Bruno Postle","updated_at":"2026-06-12T20:55:31Z","started_at":"2026-06-12T13:13:09Z","closed_at":"2026-06-12T20:55:31Z","close_reason":"Graph edges/widths match Perl on all 35 corpus files (2 bugs fixed: empty-string boundary excluded by Python 'in' operator substring check, and upper-storey rotation not delegating to below-link). Merge_Divided ported. Vertical-connectivity fidelity decision recorded in graph.py module docstring (faithful stub, no spatial overlap). Tests in test_graph.py.","dependency_count":0,"dependent_count":1,"comment_count":0}
{"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.24x1.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}
{"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}
{"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}
{"id":"homemaker-py-s44","title":"Adjacency-aware constructive seeding (cut adjacency/access fails)","description":"Follow-up to homemaker-py-c4c.2. constructive_topology currently assigns room types to leaves at RANDOM, ignoring each space's adjacency requirement. On harbor this leaves 8 adjacency + 13 access fails in the seeded design. Cluster each required room near its required neighbour (esp. circulation c) at construction time — e.g. assign rooms to leaves whose sibling/parent is C, or grow the tree so each room lands adjacent to a circulation spine. Should directly cut the adjacency+access fail load that now dominates the complete-design quality-fail regime (DESIGN.md §11.2 verdict).","status":"open","priority":2,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-17T21:50:01Z","created_by":"Bruno Postle","updated_at":"2026-06-17T21:50:01Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-c4c.5","title":"Topology diversity: structural niching + restarts (replace fitness-scalar dedup)","description":"The population dedups on the FITNESS SCALAR (driver.py:174, abs(fitness) within 1e-9) and replaces worst-by-key. There is no structural/topological diversity preservation, no restarts, no islands. On a rugged combinatorial landscape this converges prematurely — and it is the root cause of the blank-slate gap (§7 Phase 2 verdict): a single mutation chain loses to urb-evolve's random-population diversity (init.dom: memetic 18 fails vs urb-evolve 6).\nAdd: (1) a topology signature (canonical tree hash / partition signature) so 'same topology, different geometry' is detectable and niching is by STRUCTURE not score; (2) diversity-preserving replacement (crowding / niching); (3) restarts or a small island model so blank-slate exploration matches urb-evolve's upfront diversity.","design":"A cheap topology-signature hash (string-encode the per-level tree + types) unblocks niching without waiting for the full canonical encoding; the canonical Polish encoding (homemaker-py-9gp) is the principled long-term signature and makes (a|b)|c == a|(b|c) collapse exactly. Wire signature into admit() in place of / alongside the fitness-scalar guard.","acceptance_criteria":"On blank-slate programme-house, memetic reaches \u003c=6 fails (matching/beating urb-evolve) at equal native-fitness budget; population structural diversity quantified (distinct topology signatures over time) before/after; recorded in DESIGN.md §11.x + bead notes.","status":"open","priority":2,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-17T19:12:54Z","created_by":"Bruno Postle","updated_at":"2026-06-17T19:12:54Z","dependencies":[{"issue_id":"homemaker-py-c4c.5","depends_on_id":"homemaker-py-9gp","type":"relates-to","created_at":"2026-06-17T20:14:46Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-c4c.5","depends_on_id":"homemaker-py-c4c","type":"parent-child","created_at":"2026-06-17T20:12:53Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-c4c.5","depends_on_id":"homemaker-py-c4c.2","type":"blocks","created_at":"2026-06-17T20:12:54Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-c4c.4","title":"Graded high-fail objective (gradient in the high-fail regime)","description":"Phase 4 (homemaker-py-yg5) chose lexicographic (-n_fails, fitness) — correct for not being FOOLED by the 0.5^n cliff (§4.9). But lexicographic-by-TOTAL-count gives almost zero selection signal in the high-fail regime: on harbor every candidate sits at ~49-74 fails, so neighbours are indistinguishable and the search has no gradient to climb. There is no partial credit for a size-fail that is nearly in range, nor for covering one more required requirement. §7 predicted penalty reshaping would 'flatten the fail cliff' for blank-slate; lexicographic did not deliver that for high counts.\nAdd a graded objective for the high-fail regime: continuous proximity per unsatisfied constraint (how close a size/width/proportion is to its band) and/or count of DISTINCT unsatisfied requirements with sub-credit, used as a tie/secondary key beneath fail-count. Must preserve: (a) inner-loop 0.5^n cliff protection (§5.4) — inner loop unchanged; (b) the missing-space hierarchy (§6) — must not make dropping a room attractive.","design":"Likely a third comparison key: (-n_fails, -n_distinct_unsatisfied_or_proximity_sum, fitness). Or a soft margin inside fail counting only in the outer comparator. Keep the scalar fitness (with 0.5^n) untouched so the inner loop is unaffected. Extends homemaker-py-yg5; reuse experiments/penalty_reshape.py harness.","acceptance_criteria":"Measured escape from a high-fail plateau on harbor and/or blank-slate programme-house that the current lex comparator cannot escape at equal budget; before/after best-fail trajectory recorded in DESIGN.md §11.x + bead notes. Inner-loop cliff protection verified unchanged (re-run the §4.9 inner-loop 0/9-regression check).","notes":"NEGATIVE RESULT (DESIGN.md §11.4). Implemented graded proximity key (-n_fails, grade, fitness) behind use_grade flag (default off): fitness._leaf_grade / score_with_grade sum f/FAIL_THRESHOLD over failing per-leaf quality factors; scalar fitness + fail count untouched. Inner-loop 0/9 regression: PASS (re-ran §4.9 part 1). Harbor staged A/B, 20000 evals, seeds 0/1/2 total fails: lex 95/96/106 (mean 99.0) vs lex+grade 99/98/102 (mean 99.7). Grade wins 1/3, loses 2/3, slightly worse on mean, NO plateau escape. Acceptance criterion (escape lex cannot achieve) NOT met. Root cause: premise falsified — within a fixed fail-tier 0.5^n is constant so fitness still spans ~6 orders of magnitude (1e-37..1e-31), giving lex's secondary fitness key a strong gradient already; grade above fitness DISPLACES it (stalls fail-reducing restructurings), below fitness is inert. High-fail plateau is a topology-basin problem -\u003e defer to §11.5 niching/restarts + 9gp canonical encoding. Code kept default-off for reproducibility / possible reuse as a §11.5 diversity signal.","status":"in_progress","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-17T19:12:18Z","created_by":"Bruno Postle","updated_at":"2026-06-18T21:20:21Z","started_at":"2026-06-18T05:31:17Z","dependencies":[{"issue_id":"homemaker-py-c4c.4","depends_on_id":"homemaker-py-c4c","type":"parent-child","created_at":"2026-06-17T20:12:18Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
2026-06-14 17:18:23 +01:00
{"id":"homemaker-py-g0b","title":"homemaker-fitness: native Python CLI replacement for urb-fitness.pl","description":"We need a Python CLI tool that replicates the behaviour of urb-fitness.pl so we can score .dom files without shelling out to Perl. The tool should: accept .dom file paths as arguments (or glob *.dom in cwd if none given), load patterns.config and costs.config from cwd and parent dir (local overrides project-level), skip scoring if .score and .fails files are already newer than the .dom (unless FORCE_UPDATE env var is set), score each .dom using fitness.Fitness.score_with_fails(), write the score to \u003cdom\u003e.score (40-digit float format), write the failures to \u003cdom\u003e.fails, print the score to stderr. Expose as homemaker-fitness entry point in pyproject.toml and as python -m homemaker_layout.fitness_cmd module. This replaces the oracle.py shelling-out path for Phase 3 native fitness.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-14T12:32:29Z","created_by":"Bruno Postle","updated_at":"2026-06-14T16:17:21Z","started_at":"2026-06-14T12:32:52Z","closed_at":"2026-06-14T16:17:21Z","close_reason":"Implemented as homemaker_layout/fitness_cmd.py with homemaker-fitness entry point; exact score parity verified against urb-fitness.pl on corpus","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-gpx","title":"Native fitness parity gap on multi-storey designs (~3.7%)","description":"During programme-house cold-start runs with the fixed level_add operator, the generated 2-storey design showed native=1.2388e-04 vs oracle=1.1944e-04 (3.7% gap), exceeding the 0.01% rel_tol in test_native_fitness_score_parity. All existing single-storey corpus files pass parity fine (73/73). Hypothesis: a subtle discrepancy in value or cost computation for multi-level trees — candidates are staircase quality, circulation connectivity, or per-storey cost accumulation. To investigate: score a sweep of known multi-storey corpus files natively vs oracle and identify which term diverges.","status":"closed","priority":2,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-06-14T09:35:34Z","created_by":"Bruno Postle","updated_at":"2026-06-17T17:39:25Z","closed_at":"2026-06-17T17:39:25Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
2026-06-13 23:40:00 +01:00
{"id":"homemaker-py-hqw","title":"Make homemaker-py standalone: remove dependency on Perl Urb package","description":"Currently tests and fitness scoring depend on the Perl Urb package (urb-fitness.pl) and corpus files in /home/bruno/src/urb/examples/. The tool should be fully standalone and not require any external Perl packages or local urb corpus paths. This includes: bundling or reimplementing any needed reference data, making the native Python fitness the default path, and ensuring tests pass without /home/bruno/src/urb present.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-13T22:27:54Z","created_by":"Bruno Postle","updated_at":"2026-06-13T22:39:28Z","started_at":"2026-06-13T22:34:20Z","closed_at":"2026-06-13T22:39:28Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-0px","title":"Blank-slate cold-start initialisation","description":"The outer search stalls when starting from init.dom (Phase 2 gate: 18 fails after 2000 evals vs urb-evolve's 6). The root cause is single-seed topology mutation chaining — building structure one room at a time gives no gradient across the large zero-feasibility region. Fix requires multi-start bootstrap: generate a diverse initial population by random topology sampling, or a greedy room-placement initialiser that satisfies adjacency/level constraints before handing off to the memetic loop. Without this the tool is only useful for refining existing designs, not designing new buildings from scratch.","acceptance_criteria":"Cold-start from init.dom reaches comparable fail count to urb-evolve within equal eval budget; tested on programme-house","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-13T21:52:15Z","created_by":"Bruno Postle","updated_at":"2026-06-13T22:28:58Z","started_at":"2026-06-13T22:24:02Z","closed_at":"2026-06-13T22:28:58Z","close_reason":"Bootstrap implemented: auto-detect bare-plot seed, generate pop_size random topologies, evaluate each at child_budget before memetic loop; 3 new tests all green","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-ccw","title":"Scaled topology search on native fitness","description":"DESIGN.md §7 Phase 3 closing step. Once native fitness passes corpus parity, re-run the Phase-2 memetic search at real scale (population/generations comparable to urb-evolve) on the native objective. This is the first point where the §1 scaling question gets a real answer.","acceptance_criteria":"Full-scale run on programme-house beats both urb-evolve and the small-scale Phase-2 result; larger programme attempted","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:38:59Z","created_by":"Bruno Postle","updated_at":"2026-06-13T21:11:13Z","started_at":"2026-06-13T20:49:27Z","closed_at":"2026-06-13T21:11:13Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-ccw","depends_on_id":"homemaker-py-uxz","type":"blocks","created_at":"2026-06-12T00:39:44Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-ccw","depends_on_id":"homemaker-py-way","type":"blocks","created_at":"2026-06-12T00:39:45Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":2,"dependent_count":1,"comment_count":0}
{"id":"homemaker-py-way","title":"Benchmark: memetic loop vs urb-evolve at equal oracle-call budget (Phase 2 gate)","description":"DESIGN.md §7 Phase 2 gate. Compare against urb-evolve from the same seeds/programmes at equal oracle-evaluation budget — NOT generations (urb-evolve has diversity injection/culling baked in, so generations are not comparable). Go/no-go: memetic loop must beat equal-budget urb-evolve. Scaling up waits for native fitness.","acceptance_criteria":"Best-fitness and failure-count comparison at \u003e=2 budgets, \u003e=3 seeds; go/no-go decision recorded in DESIGN.md","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:37:28Z","created_by":"Bruno Postle","updated_at":"2026-06-13T08:55:03Z","started_at":"2026-06-12T21:13:20Z","closed_at":"2026-06-13T08:55:03Z","close_reason":"Phase-2 gate run (benchmark_vs_urbevolve.py, 2026-06-13, 2000 evals, URB_NO_OCCLUSION=1): 2/3 seeds → REVIEW. Memetic beats urb-evolve by 1.91x/1.63x on seeded designs; blank-slate init.dom stalls at 18 fails vs urb-evolve's 6 (random-pop init advantage). Fix: patterns.config was missing from re-score cwd (run_search.py), giving false near-zero finals in first run. Results recorded in DESIGN.md §7 Phase 2 gate.","dependencies":[{"issue_id":"homemaker-py-way","depends_on_id":"homemaker-py-b39","type":"blocks","created_at":"2026-06-12T00:39:39Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-way","depends_on_id":"homemaker-py-gp2","type":"blocks","created_at":"2026-06-12T08:27:45Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":2,"dependent_count":1,"comment_count":0}
{"id":"homemaker-py-b39","title":"Memetic search driver, small-scale (budgets in oracle evaluations)","description":"DESIGN.md §5, §7 Phase 2, §4.6 arithmetic. Memetic EA/SA over topology genomes wrapping the geometry inner loop (warm-started per §5.6); score = best full fitness over the inner loop. Explicitly small-scale on the batched oracle: tens of topologies, budget accounted in oracle evaluations, not generations. Population evaluation batched into single oracle calls.","acceptance_criteria":"End-to-end run on programme-house completes within a stated oracle-call budget and logs evaluations; produces valid .dom output","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:37:27Z","created_by":"Bruno Postle","updated_at":"2026-06-12T21:10:05Z","started_at":"2026-06-12T13:13:53Z","closed_at":"2026-06-12T21:10:05Z","close_reason":"driver.search() lands: steady-state memetic GA, tournament selection, operators + crossover, warm-started inner loop (Lamarckian write-back), budgets accounted in oracle evaluations. Acceptance run (URB_NO_OCCLUSION=1, budget 2000, seed c964435): 2010 evals / 23 topologies, best 0.00765/2 fails via crossover = x1.14 over the geometry-only optimum; output .dom re-scores standalone at exactly the recorded fitness. En route: found + fixed Urb ratio_o/ratio_type first-match nondeterminism (class-sum patch, 35/35 corpus parity) after the search reward-hacked it; operators now emit canonical uppercase generics (Bruno's correction: C=circulation, Is_Covered is a predicate).","dependencies":[{"issue_id":"homemaker-py-b39","depends_on_id":"homemaker-py-1p0","type":"blocks","created_at":"2026-06-12T00:39:37Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-b39","depends_on_id":"homemaker-py-nyb","type":"blocks","created_at":"2026-06-12T00:39:38Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":2,"dependent_count":1,"comment_count":0}
{"id":"homemaker-py-nyb","title":"High-locality topology operators (mutation + subtree crossover)","description":"DESIGN.md §5, §7 Phase 2, §8.4. Mutation moves: divide/undivide leaf, swap children, rotate cut, retype leaf, per-floor delta edits, storey add/delete (cf. Urb Mutate.pm — but geometry sliding belongs to the inner loop, not the operator set). Crossover: area-matched subtree exchange (a subtree = a contiguous region, so crossover is meaningful — Crossover.pm). Operators must be high-locality: small genome change =\u003e small phenotype change, so warm-started inner loops stay cheap.","acceptance_criteria":"Each operator produces valid genomes (oracle scores them without error); locality measured (mean fitness/geometry perturbation per operator)","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:37:27Z","created_by":"Bruno Postle","updated_at":"2026-06-12T13:07:37Z","started_at":"2026-06-12T12:54:23Z","closed_at":"2026-06-12T13:07:37Z","close_reason":"operators.py lands: 7 mutations + area-matched crossover, valid-by-construction via genome.encode repair. 115/115 oracle-valid children; locality measured: geom-pert 0.07-0.33 per op, fitness-pert 0.68-0.99 (0.5^n cliff flags raw moves — warm restart + penalty reshaping confirmed load-bearing). Also fixed dom._link stale below-links on structural mutation.","dependencies":[{"issue_id":"homemaker-py-nyb","depends_on_id":"homemaker-py-k2g","type":"blocks","created_at":"2026-06-12T00:39:36Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
{"id":"homemaker-py-k2g","title":"Topology genome: base-floor tree + per-floor deltas + type assignment","description":"DESIGN.md §5.2, §7 Phase 2. Genome = base-floor slicing topology (primary) + per-leaf type assignment + per-floor divide/undivide deltas (Below-inheritance as regulariser; cut owned by lowest storey where its path is divided — §10). Must round-trip to/from dom.py Node trees so the oracle and inner loop consume it directly. Includes storey count and per-floor type overrides.","acceptance_criteria":"Genome \u003c-\u003e .dom round-trip on all 35 corpus files preserves fitness; multi-storey wall stacking preserved","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:37:26Z","created_by":"Bruno Postle","updated_at":"2026-06-12T12:52:34Z","started_at":"2026-06-12T10:55:21Z","closed_at":"2026-06-12T12:52:34Z","close_reason":"genome.py encode/decode lands. 35/35 oracle fitness parity after round-trip (flag-on); genome fixed-point + owned-projection tests. Dead-field discovery: corpus upper storeys carry drifted dead divisions (97) and rotations (187) — canonicalised by decode, validated fitness-neutral.","dependency_count":0,"dependent_count":1,"comment_count":0}
{"id":"homemaker-py-d0s","title":"Experiment: inner-loop optimiser bake-off at equal oracle budgets","description":"DESIGN.md §7 Phase 1, §8.3. DOF is only ~rooms-1 (67 on corpus). Compare Nelder-Mead vs CMA-ES vs batched multi-start pattern search at equal oracle-call budgets, measuring fitness gained per oracle call and wall-clock (batch-friendliness matters — §4.6). Measure, don't commit blind.","acceptance_criteria":"Table of fitness-per-budget across \u003e=3 candidates; one optimiser chosen and recorded in DESIGN.md","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:36:59Z","created_by":"Bruno Postle","updated_at":"2026-06-13T08:48:13Z","started_at":"2026-06-12T21:22:15Z","closed_at":"2026-06-13T08:48:13Z","close_reason":"Bake-off complete: CMA-ES confirmed as Phase 1/2 optimiser. NM wins quality per eval but sequential architecture incompatible with batching (§4.6). Compass stalls on narrow valleys. Results in DESIGN.md §8.3 and experiments/bakeoff_innerloop.*","dependencies":[{"issue_id":"homemaker-py-d0s","depends_on_id":"homemaker-py-1p0","type":"blocks","created_at":"2026-06-12T00:39:35Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-n5k","title":"Config inheritance: load parent patterns.config/costs.config as base layer","description":"urb-evolve.pl walks up one directory level and loads ../patterns.config and ../costs.config as a base configuration before merging the programme directory's own files on top (local keys win). homemaker-evolve and fitness.load_config should replicate this: when loading a programme directory, first check the parent for each config file and load it, then deep-merge the local file over the top. This lets shared defaults live in a project root while individual programmes only override what differs.","status":"closed","priority":3,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-14T06:22:38Z","created_by":"Bruno Postle","updated_at":"2026-06-14T06:50:27Z","closed_at":"2026-06-14T06:50:27Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-9t6","title":"Package install: pyproject.toml with entry points","description":"The project currently requires PYTHONPATH=/home/bruno/src/homemaker-py/src and is run via 'python3 experiments/...'. There is no installable package. Add a pyproject.toml with: package discovery for src/homemaker/, a [project.scripts] entry point for homemaker-evolve (homemaker-py-2wc), and minimal metadata. After 'pip install -e .' the tool should be on PATH and importable without PYTHONPATH. Keep the existing pyproject.toml if one exists and extend it.","acceptance_criteria":"'pip install -e .' succeeds; 'homemaker-evolve --help' works from any directory; 'import homemaker' works without PYTHONPATH","status":"closed","priority":3,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-13T21:52:35Z","created_by":"Bruno Postle","updated_at":"2026-06-14T07:18:42Z","started_at":"2026-06-14T06:52:28Z","closed_at":"2026-06-14T07:18:42Z","close_reason":"pyproject.toml already had entry point; renamed package to homemaker-layout throughout, GitHub repo renamed, pip install -e . verified","dependencies":[{"issue_id":"homemaker-py-9t6","depends_on_id":"homemaker-py-2wc","type":"blocks","created_at":"2026-06-13T22:52:41Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-gug","title":"Test suite","description":"There are no automated tests. Validation has been done entirely through experiment scripts and the 35-file corpus parity check (homemaker-py-uxz). This is acceptable during exploration but fragile as the codebase grows. Need pytest-based unit tests covering: geometry port correctness (vs known values, not just vs oracle), fitness term correctness (size/width/proportion/adjacency/access/crinkliness/stair terms individually), genome operators (mutations preserve tree invariants), inner loop (convergence on known landscape), and a fast corpus smoke test (subset of the 35 files, score within tolerance). The corpus parity experiment can be the integration test baseline.","acceptance_criteria":"pytest runs clean; geometry, fitness terms, operators, and inner loop each have unit tests; corpus smoke test covers at least 5 files","status":"closed","priority":3,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-13T21:52:31Z","created_by":"Bruno Postle","updated_at":"2026-06-13T22:51:04Z","started_at":"2026-06-13T22:40:56Z","closed_at":"2026-06-13T22:51:04Z","close_reason":"Added test_geometry.py (26 tests) and test_fitness.py (35 tests); full suite now 175 tests, all passing","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-5l6","title":"Parallelise outer search population evaluation","description":"The outer memetic search evaluates topologies sequentially. Each eval runs the inner loop (CMA-ES) to convergence — independent across population members. Native fitness is pure Python with no shared mutable state, so population evaluation is embarrassingly parallel. multiprocessing.Pool or concurrent.futures.ProcessPoolExecutor over the child generation batch would give near-linear speedup with population size. At 71.8 evals/s single-threaded on a seeded programme-house run, parallelisation across available cores would proportionally increase the effective budget within the same wall-clock time.","acceptance_criteria":"Population generation parallelised; throughput scales with core count; verified correct (same result distribution as serial)","status":"closed","priority":3,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-13T21:52:29Z","created_by":"Bruno Postle","updated_at":"2026-06-14T05:55:16Z","started_at":"2026-06-14T05:37:13Z","closed_at":"2026-06-14T05:55:16Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-d6d","title":"Revisit Nelder-Mead for inner loop (post-oracle)","description":"The Phase 1 bakeoff (homemaker-py-d0s) chose CMA-ES over Nelder-Mead because CMA batches oracle calls (18 vs 200 per topology) — critical when oracle cost is 1 s/dom. That constraint is gone: native fitness evaluates at 71.8 evals/s with no batching penalty. The bakeoff showed NM wins quality per eval by +15% at budget 200 (x1.56 vs x1.41 gain). NM is also simpler, has no hyperparameters, and is inherently sequential which matches the inner loop's single-topology use. Re-run the bakeoff with native fitness; if NM still wins, swap it in. Also evaluate gradient-based optimisation (autograd through the native fitness functions) as a potential further improvement.","acceptance_criteria":"Bakeoff re-run with native fitness; inner loop updated if NM or gradient method outperforms CMA-ES; gain improvement documented","status":"closed","priority":3,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-13T21:52:27Z","created_by":"Bruno Postle","updated_at":"2026-06-14T07:51:35Z","closed_at":"2026-06-14T07:51:35Z","close_reason":"NM swapped in as default; bakeoff shows wins at all DOF sizes — programme-house +9% at budget 80, harbor-house decisive win (CMA harmful at 35-40 DOF)","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-2wc","title":"CLI tool: homemaker-evolve (equivalent to urb-evolve.pl)","description":"Wrap the existing memetic search driver as a proper command-line tool, analogous to urb-evolve.pl. The tool should: accept a programme directory and optional seed .dom file as positional args; honour env vars for budget/population (MAX_ITERATIONS, MAX_POP or equivalents); write the best .dom found to the programme directory (or stdout); print progress to stderr; handle SIGINT/SIGTERM gracefully (write best-so-far and exit cleanly). The bulk of the logic already exists in driver.py and experiments/run_search_scaled.py — this is a thin wrapper that makes the search usable from the shell and composable with other tools. Install as bin/homemaker-evolve or src/homemaker/bin/homemaker-evolve.","status":"closed","priority":3,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-13T21:47:55Z","created_by":"Bruno Postle","updated_at":"2026-06-14T06:50:39Z","started_at":"2026-06-14T06:01:30Z","closed_at":"2026-06-14T06:50:39Z","close_reason":"Closed","dependency_count":0,"dependent_count":1,"comment_count":0}
{"id":"homemaker-py-8fe","title":"Fix Urb programme width default (upstream of homemaker-py-can fix)","description":"The native fitness fix in homemaker-py-can derives a sane width from sqrt(size/proportion) when a programme space has no explicit width. The same bug exists upstream in Perl Urb: Fitness/Base.pm and ProgrammeDriven.pm fall back to width_inside [4.0, 1.0] for any programme space without an explicit width key. Fix the Perl oracle to match the native behaviour (same sqrt(size/proportion) formula).","status":"closed","priority":3,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-13T21:18:19Z","created_by":"Bruno Postle","updated_at":"2026-06-13T22:14:17Z","started_at":"2026-06-13T21:43:33Z","closed_at":"2026-06-13T22:14:17Z","close_reason":"Fixed: get_space_params now derives width from sqrt(size/proportion) when no explicit width key is present. 34/36 corpus files score higher with the fix; all 111 tests pass after rescoring with URB_NO_OCCLUSION=1.","dependency_count":0,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-9gp","title":"Canonical slicing encoding (normalized Polish expression) + shape feasibility","description":"DESIGN.md §5.5, §7 Phase 5. Representation upgrade once core lands: normalized Polish expression / skewed slicing tree (WongLiu) for redundancy-free, high-locality topology moves (M1/M2/M3); bottom-up shape-feasibility checks to prune infeasible topologies before the inner loop. Goal: scale to larger programmes. Excluded representations stay excluded (§2): no sequence-pair/B*-tree (non-slicing).","acceptance_criteria":"Encoding round-trips with the genome; M1/M2/M3 moves implemented; measured search improvement on a larger-than-house programme","notes":"Survey 2026-06-17: current encoding is base-floor slicing tree + per-storey deltas (GNode), not a Polish expression. 11 mutation operators work on decoded Node trees. Redundancy within the encoding is eliminated by decode() fixed-point, but tree structure itself is not canonical (a|b)|c vs a|(b|c) are distinct genomes for the same partition. M1/M2/M3 Wong-Liu moves not implemented. No pre-inner-loop shape feasibility pruning. Native fitness (homemaker-py-mz5) and parity gap (homemaker-py-gpx) are now both closed, so the explicit DESIGN.md defer condition is met. Work is justified at \u003e16 rooms where redundancy and coarse moves hurt search. Genome: genome.py, operators: operators.py, tests: test_genome.py, test_operators.py.\nReframed 2026-06-17 under epic homemaker-py-c4c (topology-search quality). This is the CAPSTONE, not the entry point: the bottleneck is topology-search QUALITY on full programmes (random room typing -\u003e missing-room stacking; flat high-fail gradient; fitness-scalar dedup), addressed first by construction (c4c.2), staging (c4c.3), graded objective (c4c.4), diversity (c4c.5). Canonical Polish encoding then lands on a search that can already construct, and provides the principled topology SIGNATURE that c4c.5 niching needs ((a|b)|c == a|(b|c) collapse). Sequence after c4c.2.","status":"open","priority":3,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-11T23:39:02Z","created_by":"Bruno Postle","updated_at":"2026-06-17T19:14:44Z","dependencies":[{"issue_id":"homemaker-py-9gp","depends_on_id":"homemaker-py-c4c.2","type":"blocks","created_at":"2026-06-17T20:14:45Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-9gp","depends_on_id":"homemaker-py-c4c.5","type":"relates-to","created_at":"2026-06-17T20:14:46Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-9gp","depends_on_id":"homemaker-py-ccw","type":"blocks","created_at":"2026-06-12T00:39:48Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-can","title":"Programme width defaults: t3 contradiction (impossible width_inside default)","description":"DESIGN.md §8.2, confirmed in source. t3 (3 m2 WC) has no width spec so inherits width_inside [4.0, 1.0] (Fitness/Base.pm:60) — geometrically impossible; designs 'pass' only by failing size instead. Fix AFTER faithful-port validation (port-faithfully-first policy, §8.1): a sane width default scaled to area (e.g. sqrt(area/proportion)) or per-room widths in patterns.config. Applies to native fitness; optionally upstream to Urb.","acceptance_criteria":"No programme space has a default width incompatible with its target area; corpus re-scored and effect documented","status":"closed","priority":3,"issue_type":"bug","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:39:01Z","created_by":"Bruno Postle","updated_at":"2026-06-13T21:21:37Z","started_at":"2026-06-13T21:16:11Z","closed_at":"2026-06-13T21:21:37Z","close_reason":"Fixed in get_space_params: when a programme space has no explicit 'width', derive target from sqrt(size/proportion) instead of falling back to width_inside [4.0, 1.0]. Re-scored 35-file corpus: 32 files improved (+1-121%), 5 files lost spurious width fails. All 109 tests pass. Upstream Perl fix tracked as homemaker-py-8fe.","dependencies":[{"issue_id":"homemaker-py-can","depends_on_id":"homemaker-py-uxz","type":"blocks","created_at":"2026-06-12T00:39:47Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-yg5","title":"Penalty reshaping: replace 0.5^n while preserving inner-loop protection","description":"DESIGN.md §4.7, §5.4, §7 Phase 4, §8.5. The 0.5^n cliff gives the outer search no gradient and rewards flag-count over geometry, but it also PROTECTS the inner loop from trading into new failures (§4.5). One fitness shape cannot naively be both soft outside and cliff-protected inside. Candidates: cliff-inside-inner-loop only, lexicographic (failure count first, score second), additive/soft, multi-objective Pareto. Must preserve the missing-space failure hierarchy (worse to drop a room than to have a poor one). Measure landscape + search outcomes; this helps Urb today too.","acceptance_criteria":"Chosen scheme documented with measurements: search improves while inner loop still never trades into new failures","status":"closed","priority":3,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:39:00Z","created_by":"Bruno Postle","updated_at":"2026-06-14T08:16:14Z","started_at":"2026-06-14T07:55:32Z","closed_at":"2026-06-14T08:16:14Z","close_reason":"Implemented lexicographic outer-search comparison (-n_fails, fitness). Inner loop unchanged (0.5^n cliff protection preserved). Experiment penalty_reshape.py confirms 0/9 fail regressions in inner loop and shows lex avoids the 3-fail trap that scalar hits 1/3 of the time. Fixed stale _CHILD_INNER_KW sigmas entry.","dependencies":[{"issue_id":"homemaker-py-yg5","depends_on_id":"homemaker-py-uxz","type":"blocks","created_at":"2026-06-12T00:39:46Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"id":"homemaker-py-2g5","title":"Rebuild occlusion/daylight/sun subsystem in Python (post-Phase-5, after optimisation fully native)","description":"DESIGN.md §6 port scope — a whole subsystem, not a term. quality_daylight (Leaf.pm:281-296) needs Urb::Misc::Sun + Urb::Field::Occlusion (+CIESky); quality_uncrinkliness also takes the occlusion object. Indoor spaces return 1 for daylight; cost is outdoor spaces + crinkliness. Port Sun_horizontal (262980-minute normalisation) and the occlusion wall set from Dom-\u003eWalls.","acceptance_criteria":"Daylight and crinkliness factors match Perl (float tolerance) across the corpus, including multi-storey cases","notes":"Re-scoped 2026-06-12: occlusion disabled in the Urb oracle instead of ported (see homemaker-py-gp2). Native fitness ships with simple crinkliness (illumination factor = 1, in homemaker-py-gnw). This issue is now the eventual Python occlusion rebuild, only after optimisation works entirely in Python. Restores outdoor-daylight and shaded-wall selection pressure.\nReframed 2026-06-17: orthogonal to epic homemaker-py-c4c. This is fitness FIDELITY (restoring daylight + shaded-wall selection pressure to match Perl), not search CAPABILITY — it changes what 'good' means, not the search's ability to find good. It will NOT improve final designs in the sense currently sought. Stays P4, deferred until the topology-search-quality epic lands and optimisation is fully native.","status":"open","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-11T23:38:25Z","created_by":"Bruno Postle","updated_at":"2026-06-17T19:14:48Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"memory","key":"deceptive-valleys-in-topology-search-when-every-single","value":"Deceptive valleys in topology search: when every single-step mutation from a target state passes through a high-fail intermediary (e.g. level_fix displaces a room into 5+ new fails), a compound operator that atomically applies two coordinated changes can escape. Design compound operators to land on the low-fail state directly, bypassing the deceptive gradient. Programme-house example: level_compound_fix atomically moves the level-constrained room AND re-inserts the displaced room adjacent to C in one step (operators.py, 2026-06-14)."}
{"_type":"memory","key":"homemaker-py-pythonpath-set-pythonpath-home-bruno-src","value":"homemaker-layout PYTHONPATH: package installed as 'homemaker-layout' via pip install -e . so 'import homemaker_layout' works from anywhere without PYTHONPATH. For running tests use 'python -m pytest' from project root /home/bruno/src/homemaker-layout (pyproject.toml adds src/ automatically). Never try pip show homemaker — that's the old homemaker-addon conflict."}
{"_type":"memory","key":"multi-storey-staircase-consistency-when-dividing-or-retyping","value":"Multi-storey staircase consistency: when dividing or retyping a circulation (C) leaf at one level, the same structural change should be propagated to the matching leaf on ALL other storeys so the stair core path is maintained. The optimizer cannot fix staircase disruptions through trial-and-error geometry alone — it requires a synchronized multi-level operator that applies the same topology change to every storey simultaneously."}
{"_type":"memory","key":"never-use-corpus-filenames-candidate-001-dom-candidate","value":"Never use corpus filenames (candidate-001.dom, candidate-002.dom, generated.dom, init.dom, etc.) as --output targets when running experiments. These are test fixtures. Always write experimental outputs to scratch/ or a timestamped path. Lesson from 2026-06-14: warm-start runs overwrote candidate-001/002.dom and broke graph tests."}
{"_type":"memory","key":"urb-fitness-bug-found-fixed-2026-06-12","value":"Urb fitness bug found+fixed 2026-06-12 (patch in /home/bruno/src/urb, uncommitted): ProgrammeDriven.pm ratio_o/ratio_type grepped case-insensitively over the ratios hash and took the FIRST key — nondeterministic (x4.5 score swings) for designs with mixed-case type classes (both 'c' circulation and 'C' covered). Fixed to SUM the class (matches Is_Circulation//Is_Outside semantics); 35/35 corpus scores unchanged. CRITICAL for homemaker-py-3y7/gnw: the native port must implement class-SUM ratios. Building.pm has the same unpatched pattern (site-driven path, not used by our oracle). Also: the memetic search reward-hacked this bug before the fix — search results predating it are noise artifacts."}
{"_type":"memory","key":"programme-house-optimisation-result-2026-06-14-15","value":"Programme-house optimisation result (2026-06-14/15): best achievable is 1 fail (l1 wrong level, score ~0.005). 0 fails is geometrically impossible: l1 (min 27m²) must occupy ll (~23m²) at level 0, which eliminates the t3-adj-C provider; dividing ll into lll(l1)+llr(C) gives llr proportion ~6:1 (fails). Python memetic optimizer achieves 1 fail in 50k evals vs Perl optimiser's 2-3 fails. Winning topology: TWO C nodes at level 0 — ll(C) for t3-adj-C via geometric contact, rl(C) for staircase via tree-sibling adjacency to rrr(O). Best .dom: scratch/from-warmstart-fixed.dom and scratch/from-compound3-fixed.dom."}
{"_type":"memory","key":"urb-oracle-nondeterminism-urb-fitness-pl-output-varies","value":"Urb oracle nondeterminism: urb-fitness.pl output varies run-to-run from Perl hash-order randomisation — .fails line ORDER shuffles (compare sorted, use oracle.Score.fail_lines) and the score float can flip by ~1 ULP (compare with math.isclose rel_tol=1e-12, never ==). Not a batching artifact; affects single runs too. Matters for the Phase 3 native-fitness parity gate (homemaker-py-uxz)."}
{"_type":"memory","key":"user-preference-bruno-this-is-a-fedora-system","value":"User preference (Bruno): this is a Fedora system — NEVER install Python packages via pip without asking first; always ask whether to install the rpm via dnf (e.g. python3-cma) before considering pip. Applies to any dependency additions."}
{"_type":"memory","key":"warm-x0-initialization-bug-pattern-when-a-topology","value":"warm_x0 initialization bug pattern: when a topology operator explicitly sets division ratios on a newly-created node (e.g. compound_fix sets node.division=[0.25,0.25] for t3), parent.ratios has no entry for that node (it was a leaf). warm_x0 defaults it to 0.5, corrupting the inner loop's starting point and making the operator invisible to lex comparison. Fix: only propagate child ratios for nodes where the parent node was NOT already divided; stale hidden nodes revealed by structural mutations (swap flipping b.below) must NOT contribute their pre-writeback values. See driver.py lines 259-267 (fixed 2026-06-14)."}
{"_type":"memory","key":"strategy-decision-2026-06-12-bruno-occlusion-daylight","value":"Strategy decision 2026-06-12 (Bruno): occlusion/daylight is ORTHOGONAL to building a scalable optimiser. Disable it in Urb (env flag, homemaker-py-gp2) rather than port it; native fitness uses simple crinkliness (illumination factor = 1); rebuild occlusion in Python only after optimisation is fully native (homemaker-py-2g5, now P4). Consequence: all scores change when the flag flips — re-baseline corpus/.score, DESIGN \\$4.5 gains, gate bars at one clean boundary AFTER homemaker-py-1p0 closes; Phase-2 urb-evolve benchmark must run with the same flag."}
{"_type":"memory","key":"adjacency-in-binary-slicing-tree-is-structural-not","value":"Adjacency in binary slicing tree is structural, not geometric: the inner-loop NM cannot fix topological adjacency failures. Two paths exist: (1) tree-sibling adjacency — a node is adjacent to its sibling in the tree; (2) cross-zone geometric adjacency — leaves from different subtrees that happen to share a boundary. Staircase/adjacency fails require a topology mutation that changes which nodes are siblings or which zones touch. This was proved empirically on programme-house: staircase fail from rot=0 layout could not be fixed by NM but was fixed by level_retype creating a two-C topology (2026-06-14/15)."}
{"_type":"memory","key":"cli-tool-style-prefer-python-m-homemaker-module","value":"CLI tool style: prefer python -m homemaker.module --parameters pattern, installable via pip install -e . with pyproject.toml entry_points. Not standalone bin/ scripts."}
{"_type":"memory","key":"correction-to-urb-fitness-bug-memory-bruno-2026","value":"CORRECTION to urb-fitness-bug memory (Bruno, 2026-06-12): 'C' is NOT a 'covered' type — Is_Covered is a geometric predicate (indoor space above). Urb's generic types are canonically UPPERCASE: C=circulation, O=outside, S=sahn (get_space_types qw/C O S/; corpus is 100% uppercase, never 'c'/'o' leaves). The mixed-case designs that fired the latent ratio_type first-match bug were created by homemaker's own operator type pool emitting lowercase 'c'/'o' — fixed: driver/operators now emit uppercase generics only, and class checks use t[0].lower() in 'cos'. The Urb class-sum patch stays as defensive hardening (zero impact on canonical designs). Native port (3y7/gnw): treat type classes case-insensitively, generics canonically uppercase."}