erc.7d/§13.7: high-budget harbor floor probe — close 71d NO-GO, wrap Phase 8
500k serial full-stack harbor probe (probe_harbor_floor.py): 20 fails, crinkliness 13→4, landlocked crinkliness ~13→2 of 20. Interior-O (default-ON, erc.8) is 71d's named fix and dissolved its landlocked-crinkliness target; residual now diffuse (top class edge-too-long). NO-GO on 71d. Cumulative Phase-8 floor vs §12.2 baseline (leaf-share-relaxed): maple 136.0→80.3 (−41%), harbor 74.0→34.0 (−54%) — all from construction levers, none from search machinery, per the epic thesis. Closes erc epic: 71d/7u5/jrb/u8x superseded-by-construction; erc.5/erc.6 wont-fix (Diag A/B revisit conditions unmet). DESIGN §13.7. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JygRv4n2dcyDQqMiDRe7TN
This commit is contained in:
parent
346e7eeb86
commit
27d7a0f771
3 changed files with 254 additions and 13 deletions
|
|
@ -22,13 +22,14 @@
|
||||||
{"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}
|
{"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}
|
||||||
{"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-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-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-71d.1","title":"Diagnostic: high-budget harbor floor on full default stack — does landlocked crinkliness still dominate after interior-O?","description":"71d go/no-go probe. 71d targets landlocked crinkliness (area_outside=0, ratio-invariant) which its named fix (interior O courtyards) addresses. interior_outside now ships default-ON (erc.8), so re-measure: run harbor full default stack at high budget (1M evals, n_workers=4, seed 0) and break down the at-convergence residual — fail-type histogram + landlocked-vs-under-exposed split of crinkliness fails. If landlocked still dominates -\u003e 71d worth it; if interior-O dissolved it -\u003e 71d redundant. Verdict to DESIGN.md.","notes":"VERDICT (DESIGN §13.7): NO-GO on 71d. 500k serial full-stack harbor probe (seed 0) -\u003e 20 fails. Crinkliness collapsed 13-\u003e4, landlocked crinkliness ~13-\u003e2 of 20. Interior-O (now default) IS 71d's named fix (interior O courtyards) and already dissolved the target block. Residual now diffuse (top class edge-too-long 6), no concentrated ratio-invariant block for a targeted operator. Recommend close 71d + 7u5/jrb/u8x as superseded-by-construction.","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-28T06:57:44Z","created_by":"Bruno Postle","updated_at":"2026-06-28T13:19:08Z","started_at":"2026-06-28T06:58:10Z","closed_at":"2026-06-28T13:19:08Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-71d.1","depends_on_id":"homemaker-py-71d","type":"parent-child","created_at":"2026-06-28T07:57:44Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-erc.8","title":"Flip interior_outside (odiv=3) default to ON","description":"§13.6/ld2 confirmed interior-O light-well seeding positive on dense floors (harbor -16.4%, all seeds improve) and net-neutral on maple (-2.8%, mean improves, no programme regresses on mean). Mirror the pll flip after erc.7: change interior_outside default False-\u003eTrue in driver.search/search_staged and operators.constructive_topology/lift_base_to_storeys (outside_divisor stays 3). No test asserts fail counts so low-risk. Verify control runs still re-score OK.","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-28T06:18:14Z","created_by":"Bruno Postle","updated_at":"2026-06-28T06:29:48Z","started_at":"2026-06-28T06:26:42Z","closed_at":"2026-06-28T06:29:48Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-erc.8","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-28T07:18:13Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-erc.8","title":"Flip interior_outside (odiv=3) default to ON","description":"§13.6/ld2 confirmed interior-O light-well seeding positive on dense floors (harbor -16.4%, all seeds improve) and net-neutral on maple (-2.8%, mean improves, no programme regresses on mean). Mirror the pll flip after erc.7: change interior_outside default False-\u003eTrue in driver.search/search_staged and operators.constructive_topology/lift_base_to_storeys (outside_divisor stays 3). No test asserts fail counts so low-risk. Verify control runs still re-score OK.","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-28T06:18:14Z","created_by":"Bruno Postle","updated_at":"2026-06-28T06:29:48Z","started_at":"2026-06-28T06:26:42Z","closed_at":"2026-06-28T06:29:48Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-erc.8","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-28T07:18:13Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-pll","title":"Flip depth_balanced + leaf_sharing (factor 3) defaults to ON","description":"erc.7/§13.5 verdict: depth_balanced + leaf_sharing (factor 3) is the winning Phase-8 stack (harbor -21%, maple -4.6% vs share-alone; factor 3 confirmed optimal). Both default OFF today. Make the bal+share stack the default in driver.search/search_staged (leaf_sharing=True, leaf_share_factor=3, depth_balanced=True) and update the affected tests (the §13.4 note records 214 tests pass with depth_balanced OFF — expect ordering/snapshot churn). Keep env-var overrides (DEPTHBAL/LEAFSHARE/LEAFSHAREFAC) for A/B. leaf_share_max stays 4 (covers factor\u003c=4, no missing-fail leak).","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-27T16:12:53Z","created_by":"Bruno Postle","updated_at":"2026-06-27T20:15:26Z","started_at":"2026-06-27T16:14:52Z","closed_at":"2026-06-27T20:15:26Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-pll","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-27T17:13:34Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-pll","title":"Flip depth_balanced + leaf_sharing (factor 3) defaults to ON","description":"erc.7/§13.5 verdict: depth_balanced + leaf_sharing (factor 3) is the winning Phase-8 stack (harbor -21%, maple -4.6% vs share-alone; factor 3 confirmed optimal). Both default OFF today. Make the bal+share stack the default in driver.search/search_staged (leaf_sharing=True, leaf_share_factor=3, depth_balanced=True) and update the affected tests (the §13.4 note records 214 tests pass with depth_balanced OFF — expect ordering/snapshot churn). Keep env-var overrides (DEPTHBAL/LEAFSHARE/LEAFSHAREFAC) for A/B. leaf_share_max stays 4 (covers factor\u003c=4, no missing-fail leak).","status":"closed","priority":2,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-27T16:12:53Z","created_by":"Bruno Postle","updated_at":"2026-06-27T20:15:26Z","started_at":"2026-06-27T16:14:52Z","closed_at":"2026-06-27T20:15:26Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-pll","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-27T17:13:34Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-9o5","title":"Multi-use leaves: one leaf satisfies several COMPATIBLE different codes (type superposition)","description":"A leaf that legitimately and simultaneously satisfies several DIFFERENT compatible programme requirements (e.g. study + guest bedroom, or kitchen + dining). Distinct from erc.3 leaf-sharing, which aggregates k instances of the SAME code; this is a strict generalisation across DIFFERENT codes. Idea from Bruno (this corresponds to Stewart Brand's 'How Buildings Learn' — loose-fit / long-life rooms whose use churns over a building's lifetime).\n\nWHY IT MATTERS\n1. Architectural deliverable: adaptable multi-use rooms (Brand loose-fit), not just an optimisation trick.\n2. Generalises the erc.3 floor-lowering lever to the SINGLETON (count:1) long tail that same-type sharing cannot reach: one leaf covering one X AND one Y removes a room-leaf, paying the ~1.8/leaf crinkliness tax (§13.1) once instead of twice. Crinkliness is scale-invariant, so a larger multi-use leaf is not penalised for size.\n\nTWO READINGS\n(a) Superposition as a SEARCH RELAXATION: carry a distribution/set of candidate types per leaf, evaluate a relaxed (expected/best-case) fitness for a smoother landscape, then COLLAPSE (argmax) at the end. Risks: relaxation gap (relaxed optimum need not sit near a good integer solution); collapse is itself a constrained rounding/assignment problem (cannot collapse 5 superposed leaves all to 'kitchen' when 1 is required); and search-machinery bets are 0/3 historically (§11-12) vs construction 4/4 — the floor is geometric, so pure search-easing may fight the wrong battle. LOWER PRIORITY framing.\n(b) Multi-use as the DESIGN GOAL (preferred): the leaf permanently serves a SET of compatible codes; no collapse needed, multi-use survives into the output. Mirrors erc.3's mechanism exactly but with a SET of codes instead of an integer count: stamp leaf with the codes it serves (type-guarded as in erc.3 leaf.share/share_type); fitness count credits each code in the set, size scored against the union/least-upper-bound of targets, width/proportion as today (scale-invariant), adjacency satisfied if the SET satisfies it.\n\nIMPLEMENTATION SKETCH (path b)\n- dom.Node: a set/list of served codes (generalises leaf.share/share_type from erc.3). Survives search via deepcopy; emit in .dom only when non-trivial (as with 'share').\n- graph.check_space_counts: a multi-use leaf credits coverage to EACH code in its set (type-guarded: honoured only while its served set is consistent with its assignment).\n- fitness size/width/proportion: score the multi-use leaf against the combined target (union/LUB) of its served codes; crinkliness/access unchanged.\n- construction: a new constructive option that fuses COMPATIBLE singleton rooms into shared multi-use leaves (analogous to operators._share_rooms but across codes), honouring adjacency/level.\n- default OFF; controls reproduce §12.2 baseline.\n\nKEY OPEN QUESTIONS (Bruno to spec)\n- Who declares type-COMPATIBILITY? A new architectural input, analogous to adjacency (e.g. a 'compatible:' / 'multiuse:' list per space in patterns.config). kitchen+bathroom is nonsensical; study+guestroom is fine.\n- Does the final design COLLAPSE to single uses or stay loose-fit (keep superposition as a deliverable)? Brand argues for keeping it.\n- How exactly to combine size/width/proportion targets for a leaf serving 2+ codes (max? union? a 'dominant use' target?).\n- Interaction with erc.3 same-type sharing and x3b per-code control — composable? (a leaf could be 'k of X' AND 'one Y').\n\nRELATES TO: erc.3 (same-type leaf-sharing, the special case), x3b (per-code shareable flag), erc.7 (factor/synergy sweep), erc epic (lower the geometry floor). Concept only — implement in a future session.","status":"open","priority":2,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-24T21:11:03Z","created_by":"Bruno Postle","updated_at":"2026-06-24T21:11:03Z","dependencies":[{"issue_id":"homemaker-py-9o5","depends_on_id":"homemaker-py-erc.3","type":"related","created_at":"2026-06-24T22:11:48Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-9o5","title":"Multi-use leaves: one leaf satisfies several COMPATIBLE different codes (type superposition)","description":"A leaf that legitimately and simultaneously satisfies several DIFFERENT compatible programme requirements (e.g. study + guest bedroom, or kitchen + dining). Distinct from erc.3 leaf-sharing, which aggregates k instances of the SAME code; this is a strict generalisation across DIFFERENT codes. Idea from Bruno (this corresponds to Stewart Brand's 'How Buildings Learn' — loose-fit / long-life rooms whose use churns over a building's lifetime).\n\nWHY IT MATTERS\n1. Architectural deliverable: adaptable multi-use rooms (Brand loose-fit), not just an optimisation trick.\n2. Generalises the erc.3 floor-lowering lever to the SINGLETON (count:1) long tail that same-type sharing cannot reach: one leaf covering one X AND one Y removes a room-leaf, paying the ~1.8/leaf crinkliness tax (§13.1) once instead of twice. Crinkliness is scale-invariant, so a larger multi-use leaf is not penalised for size.\n\nTWO READINGS\n(a) Superposition as a SEARCH RELAXATION: carry a distribution/set of candidate types per leaf, evaluate a relaxed (expected/best-case) fitness for a smoother landscape, then COLLAPSE (argmax) at the end. Risks: relaxation gap (relaxed optimum need not sit near a good integer solution); collapse is itself a constrained rounding/assignment problem (cannot collapse 5 superposed leaves all to 'kitchen' when 1 is required); and search-machinery bets are 0/3 historically (§11-12) vs construction 4/4 — the floor is geometric, so pure search-easing may fight the wrong battle. LOWER PRIORITY framing.\n(b) Multi-use as the DESIGN GOAL (preferred): the leaf permanently serves a SET of compatible codes; no collapse needed, multi-use survives into the output. Mirrors erc.3's mechanism exactly but with a SET of codes instead of an integer count: stamp leaf with the codes it serves (type-guarded as in erc.3 leaf.share/share_type); fitness count credits each code in the set, size scored against the union/least-upper-bound of targets, width/proportion as today (scale-invariant), adjacency satisfied if the SET satisfies it.\n\nIMPLEMENTATION SKETCH (path b)\n- dom.Node: a set/list of served codes (generalises leaf.share/share_type from erc.3). Survives search via deepcopy; emit in .dom only when non-trivial (as with 'share').\n- graph.check_space_counts: a multi-use leaf credits coverage to EACH code in its set (type-guarded: honoured only while its served set is consistent with its assignment).\n- fitness size/width/proportion: score the multi-use leaf against the combined target (union/LUB) of its served codes; crinkliness/access unchanged.\n- construction: a new constructive option that fuses COMPATIBLE singleton rooms into shared multi-use leaves (analogous to operators._share_rooms but across codes), honouring adjacency/level.\n- default OFF; controls reproduce §12.2 baseline.\n\nKEY OPEN QUESTIONS (Bruno to spec)\n- Who declares type-COMPATIBILITY? A new architectural input, analogous to adjacency (e.g. a 'compatible:' / 'multiuse:' list per space in patterns.config). kitchen+bathroom is nonsensical; study+guestroom is fine.\n- Does the final design COLLAPSE to single uses or stay loose-fit (keep superposition as a deliverable)? Brand argues for keeping it.\n- How exactly to combine size/width/proportion targets for a leaf serving 2+ codes (max? union? a 'dominant use' target?).\n- Interaction with erc.3 same-type sharing and x3b per-code control — composable? (a leaf could be 'k of X' AND 'one Y').\n\nRELATES TO: erc.3 (same-type leaf-sharing, the special case), x3b (per-code shareable flag), erc.7 (factor/synergy sweep), erc epic (lower the geometry floor). Concept only — implement in a future session.","status":"open","priority":2,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-24T21:11:03Z","created_by":"Bruno Postle","updated_at":"2026-06-24T21:11:03Z","dependencies":[{"issue_id":"homemaker-py-9o5","depends_on_id":"homemaker-py-erc.3","type":"related","created_at":"2026-06-24T22:11:48Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-x3b","title":"Per-code shareable flag (SpaceReq.share) + homemaker-evolve CLI wiring","description":"Make leaf-sharing (erc.3, §13.3) safe to default-on by giving the programme author per-code control, and expose it on the real CLI (not just the experiment env var).\n\nDesign (agreed with Bruno, open to refinement — he has follow-up questions):\n- patterns.config per-space optional key 'share: N' -\u003e SpaceReq.share (int, default 1 = not shareable). N\u003e=2 means up to N rooms of this code per shared leaf.\n- Master enable stays the 'leaf_sharing' conf/CLI flag (default OFF -\u003e baseline, controls reproduce).\n- Global grain selector 'leaf_share_factor': 0 =\u003e per-code opt-in only (share a code iff it has share:N\u003e=2); F\u003e=2 =\u003e global mode (share all sized multi-instance codes at grain F) with per-code 'share' overriding (share:1 opts a code OUT). This single knob covers both the safe default-on philosophy (0 + per-code keys) and the §13.3 experiment (F=3, reproducible, no example-programme edits).\n- operators._share_rooms picks grain per code accordingly; fitness honours the explicit leaf.share (type-guarded) as today.\n- homemaker-evolve gains --leaf-sharing / --leaf-share-factor, threaded to driver.search/search_staged (already plumbed).\n- Tests: per-code grain, opt-out, default-OFF parity. NOT editing example programmes so §13.3 stays reproducible.\n\nRelates to dyh (productionise). erc.7 covers the factor/max_share sweep + erc.4 synergy.","status":"open","priority":2,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-24T21:03:05Z","created_by":"Bruno Postle","updated_at":"2026-06-24T21:14:56Z","started_at":"2026-06-24T21:03:45Z","dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-x3b","title":"Per-code shareable flag (SpaceReq.share) + homemaker-evolve CLI wiring","description":"Make leaf-sharing (erc.3, §13.3) safe to default-on by giving the programme author per-code control, and expose it on the real CLI (not just the experiment env var).\n\nDesign (agreed with Bruno, open to refinement — he has follow-up questions):\n- patterns.config per-space optional key 'share: N' -\u003e SpaceReq.share (int, default 1 = not shareable). N\u003e=2 means up to N rooms of this code per shared leaf.\n- Master enable stays the 'leaf_sharing' conf/CLI flag (default OFF -\u003e baseline, controls reproduce).\n- Global grain selector 'leaf_share_factor': 0 =\u003e per-code opt-in only (share a code iff it has share:N\u003e=2); F\u003e=2 =\u003e global mode (share all sized multi-instance codes at grain F) with per-code 'share' overriding (share:1 opts a code OUT). This single knob covers both the safe default-on philosophy (0 + per-code keys) and the §13.3 experiment (F=3, reproducible, no example-programme edits).\n- operators._share_rooms picks grain per code accordingly; fitness honours the explicit leaf.share (type-guarded) as today.\n- homemaker-evolve gains --leaf-sharing / --leaf-share-factor, threaded to driver.search/search_staged (already plumbed).\n- Tests: per-code grain, opt-out, default-OFF parity. NOT editing example programmes so §13.3 stays reproducible.\n\nRelates to dyh (productionise). erc.7 covers the factor/max_share sweep + erc.4 synergy.","status":"open","priority":2,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-24T21:03:05Z","created_by":"Bruno Postle","updated_at":"2026-06-24T21:14:56Z","started_at":"2026-06-24T21:03:45Z","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-erc.7","title":"Leaf-sharing × erc.4 depth-balancing synergy + factor/max_share sweep","description":"With the missing-fail leak closed by explicit multiplicity (§13.3), revisit the erc.3↔erc.4 synergy the diagnostics predicted: depth-balanced construction lands shared leaves at their correct absolute k×target area, which should further cut size+crinkliness. Also sweep leaf_share_factor (3 won here; try 2/4) and leaf_share_max (default 4) on maple+harbor, seeds 0/1/2, staged 20k, vs the §13.3 factor-3 result (maple 86.3, harbor 50.3).","notes":"FACTOR SWEEP DONE (§13.5): factor 3 confirmed default under bal+share. maple f2=92.7 f3=82.3 f4=83.3; harbor f2=53.0 f3=40.0 f4=39.7. Factor 2 regresses both; f3/f4 tied within noise (f3 wins maple +1.0, f4 wins harbor +0.3). leaf_share_max=4 covers factor\u003c=4, no missing-fail leak (re-score OK all runs). erc.7 complete.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-24T20:51:43Z","created_by":"Bruno Postle","updated_at":"2026-06-27T09:55:56Z","started_at":"2026-06-26T07:39:54Z","closed_at":"2026-06-27T09:55:56Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-erc.7","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-24T21:51:42Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-erc.7","title":"Leaf-sharing × erc.4 depth-balancing synergy + factor/max_share sweep","description":"With the missing-fail leak closed by explicit multiplicity (§13.3), revisit the erc.3↔erc.4 synergy the diagnostics predicted: depth-balanced construction lands shared leaves at their correct absolute k×target area, which should further cut size+crinkliness. Also sweep leaf_share_factor (3 won here; try 2/4) and leaf_share_max (default 4) on maple+harbor, seeds 0/1/2, staged 20k, vs the §13.3 factor-3 result (maple 86.3, harbor 50.3).","notes":"FACTOR SWEEP DONE (§13.5): factor 3 confirmed default under bal+share. maple f2=92.7 f3=82.3 f4=83.3; harbor f2=53.0 f3=40.0 f4=39.7. Factor 2 regresses both; f3/f4 tied within noise (f3 wins maple +1.0, f4 wins harbor +0.3). leaf_share_max=4 covers factor\u003c=4, no missing-fail leak (re-score OK all runs). erc.7 complete.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-24T20:51:43Z","created_by":"Bruno Postle","updated_at":"2026-06-27T09:55:56Z","started_at":"2026-06-26T07:39:54Z","closed_at":"2026-06-27T09:55:56Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-erc.7","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-24T21:51:42Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-dyh","title":"Productionise leaf-sharing: evolve CLI flag + patterns.config key","description":"erc.3 (§13.3) proved leaf-sharing lowers the floor −37% maple / −32% harbor end-to-end, but the flag is only reachable via the LEAFSHARE env in run_staged_search.py. For real runs: (1) expose --leaf-sharing / --leaf-share-factor on homemaker-evolve (evolve.py), threading to driver.search/search_staged (already plumbed); (2) optionally read a leaf_sharing key from patterns.config so the fitness + construction stay consistent without env injection (fitness already reads conf; construction would read it in evolve). Consider whether to default it ON given the decisive win. Also: the genome.signature ignores leaf.share, so a shared vs unshared leaf of the same type/structure collide — assess if niching needs share in the signature.","status":"closed","priority":2,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-24T20:51:41Z","created_by":"Bruno Postle","updated_at":"2026-06-24T21:03:47Z","closed_at":"2026-06-24T21:03:47Z","close_reason":"Superseded by x3b (per-code shareable flag + CLI wiring), which is the concrete implementation of dyh's 'CLI flag + patterns.config key' scope with the per-code opt-in design.","dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-dyh","title":"Productionise leaf-sharing: evolve CLI flag + patterns.config key","description":"erc.3 (§13.3) proved leaf-sharing lowers the floor −37% maple / −32% harbor end-to-end, but the flag is only reachable via the LEAFSHARE env in run_staged_search.py. For real runs: (1) expose --leaf-sharing / --leaf-share-factor on homemaker-evolve (evolve.py), threading to driver.search/search_staged (already plumbed); (2) optionally read a leaf_sharing key from patterns.config so the fitness + construction stay consistent without env injection (fitness already reads conf; construction would read it in evolve). Consider whether to default it ON given the decisive win. Also: the genome.signature ignores leaf.share, so a shared vs unshared leaf of the same type/structure collide — assess if niching needs share in the signature.","status":"closed","priority":2,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-24T20:51:41Z","created_by":"Bruno Postle","updated_at":"2026-06-24T21:03:47Z","closed_at":"2026-06-24T21:03:47Z","close_reason":"Superseded by x3b (per-code shareable flag + CLI wiring), which is the concrete implementation of dyh's 'CLI flag + patterns.config key' scope with the per-code opt-in design.","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-7u5","title":"Thread parent failure strings onto Individual","description":"Store the sorted .fails tuple on driver.Individual so operators can read which constraints the parent violates. The score is already recomputed per child (driver.py:146 want_grade path / innerloop result); capture score_with_fails output instead of discarding the strings. Near-zero cost. Prereq for the repair operator (homemaker-py-71d).","notes":"Also feeds erc.1 (per-leaf shape-fail vs density/granularity profile): storing the sorted .fails on Individual makes per-leaf fail attribution available to the diagnostic without re-scoring. Cheap, generically useful — promote ahead of the Tier-3 operator work if erc.1 is picked up first.","status":"open","priority":2,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-23T20:40:17Z","created_by":"Bruno Postle","updated_at":"2026-06-23T20:50:25Z","dependencies":[{"issue_id":"homemaker-py-7u5","depends_on_id":"homemaker-py-71d","type":"parent-child","created_at":"2026-06-23T21:49:52Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":1,"comment_count":0}
|
{"id":"homemaker-py-7u5","title":"Thread parent failure strings onto Individual","description":"Store the sorted .fails tuple on driver.Individual so operators can read which constraints the parent violates. The score is already recomputed per child (driver.py:146 want_grade path / innerloop result); capture score_with_fails output instead of discarding the strings. Near-zero cost. Prereq for the repair operator (homemaker-py-71d).","notes":"Also feeds erc.1 (per-leaf shape-fail vs density/granularity profile): storing the sorted .fails on Individual makes per-leaf fail attribution available to the diagnostic without re-scoring. Cheap, generically useful — promote ahead of the Tier-3 operator work if erc.1 is picked up first.","status":"closed","priority":2,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-23T20:40:17Z","created_by":"Bruno Postle","updated_at":"2026-06-28T13:21:50Z","closed_at":"2026-06-28T13:21:50Z","close_reason":"Superseded by construction (DESIGN §13.7): interior-O (default-ON, erc.8) is 71d's named fix (interior O courtyards) and collapsed landlocked crinkliness ~13-\u003e2 of 20 in the high-budget probe. Residual now diffuse, no concentrated ratio-invariant block for a targeted repair operator. Reopen/refile if a future floor probe shows a concentrated ratio-invariant class return.","dependencies":[{"issue_id":"homemaker-py-7u5","depends_on_id":"homemaker-py-71d","type":"parent-child","created_at":"2026-06-23T21:49:52Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":1,"comment_count":0}
|
||||||
{"id":"homemaker-py-xcy","title":"Constructive seeder is nondeterministic across processes (id-based set iteration)","description":"BUG / reproducibility. operators._assign_adjacency_aware builds Python sets of dom.Node objects (circ/dominated/frontier) and iterates them; set iteration order for objects is id()-based, which varies across processes. Result: constructive_topology(seed=0, adjacency_aware=True) yields DIFFERENT topology signatures in separate processes (verified: sig hashes 4480 vs 16064 for maple-court seed 0), so the whole staged search trajectory is non-reproducible run-to-run. Measured single-run noise ~±3 fails (c3g div=3 control 129 vs §12.3 126 for the same maple seed 0). IMPACT: per-seed numbers in the §11/§12 ledger are not reproducible; only multi-seed MEANS are stable, and small effects (±3-4, e.g. the §12.3 negatives) are near the noise floor. FIX: make the dominating-set/assignment iteration deterministic — sort candidate nodes by the existing idx (leaf index) instead of relying on set iteration order, or drive all tie-breaks through idx. Re-establishing determinism will shift baselines slightly; note in DESIGN.md. Files: operators._assign_adjacency_aware (circ set, dominated union, frontier, the for s in circ loops).","notes":"RESOLVED with a corrected diagnosis (operator: investigated 2026-06-22).\n\nMISDIAGNOSIS: the constructive seeder is NOT nondeterministic. _assign_adjacency_aware ends every max/min with a unique idx tiebreak (-idx[L]); its set unions (circ/dominated/frontier) are used only for membership, so iteration order never leaks. Proven: constructive_topology(seed=0, adjacency_aware AND not) gives BYTE-IDENTICAL signatures across processes for all four example programmes (stable sha1, e.g. maple-court aa=e688f744326b in 3 separate processes). The cited '4480 vs 16064' was a MEASUREMENT ARTIFACT: Python's builtin hash() of a str is salted per-process (PYTHONHASHSEED), so hashing an IDENTICAL signature string in two processes yields different ints (reproduced: 51920/5342/59970 for one identical string). Serial search (workers=1) is byte-for-byte reproducible (identical .dom across runs).\n\nREAL BUG (fixed): parallel-only nondeterminism in driver._run_batch. It admitted futures via concurrent.futures.as_completed -\u003e completion order varies run-to-run, and admit() is order-sensitive (accrues n_evals per result; keeps the FIRST individual of an equal-key tie as best). A long parallel run diverged 167 vs 161 fails (maple seed 0) — the real source of the +-3..6 'noise'. FIX: iterate the futures list in SUBMISSION order (block on each f.result() in turn; all still run concurrently), reproducing the serial admission sequence. After fix: two workers=4 runs are byte-identical (162 fails, identical .dom). 211 tests pass.\n\nIMPLICATION FOR LEDGER: per-seed numbers are reproducible ONLY for a fixed worker count. Serial != parallel is EXPECTED (children-per-iteration = 1 vs n_workers changes batch granularity, hence the search), not nondeterminism. Any ledger A/B comparing runs at DIFFERENT worker counts (or pre-fix parallel) conflated this with a real effect — re-run sub-+-3 effects at a fixed worker count.","status":"closed","priority":2,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-06-21T20:39:09Z","created_by":"Bruno Postle","updated_at":"2026-06-22T22:13:17Z","closed_at":"2026-06-22T22:13:17Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-xcy","title":"Constructive seeder is nondeterministic across processes (id-based set iteration)","description":"BUG / reproducibility. operators._assign_adjacency_aware builds Python sets of dom.Node objects (circ/dominated/frontier) and iterates them; set iteration order for objects is id()-based, which varies across processes. Result: constructive_topology(seed=0, adjacency_aware=True) yields DIFFERENT topology signatures in separate processes (verified: sig hashes 4480 vs 16064 for maple-court seed 0), so the whole staged search trajectory is non-reproducible run-to-run. Measured single-run noise ~±3 fails (c3g div=3 control 129 vs §12.3 126 for the same maple seed 0). IMPACT: per-seed numbers in the §11/§12 ledger are not reproducible; only multi-seed MEANS are stable, and small effects (±3-4, e.g. the §12.3 negatives) are near the noise floor. FIX: make the dominating-set/assignment iteration deterministic — sort candidate nodes by the existing idx (leaf index) instead of relying on set iteration order, or drive all tie-breaks through idx. Re-establishing determinism will shift baselines slightly; note in DESIGN.md. Files: operators._assign_adjacency_aware (circ set, dominated union, frontier, the for s in circ loops).","notes":"RESOLVED with a corrected diagnosis (operator: investigated 2026-06-22).\n\nMISDIAGNOSIS: the constructive seeder is NOT nondeterministic. _assign_adjacency_aware ends every max/min with a unique idx tiebreak (-idx[L]); its set unions (circ/dominated/frontier) are used only for membership, so iteration order never leaks. Proven: constructive_topology(seed=0, adjacency_aware AND not) gives BYTE-IDENTICAL signatures across processes for all four example programmes (stable sha1, e.g. maple-court aa=e688f744326b in 3 separate processes). The cited '4480 vs 16064' was a MEASUREMENT ARTIFACT: Python's builtin hash() of a str is salted per-process (PYTHONHASHSEED), so hashing an IDENTICAL signature string in two processes yields different ints (reproduced: 51920/5342/59970 for one identical string). Serial search (workers=1) is byte-for-byte reproducible (identical .dom across runs).\n\nREAL BUG (fixed): parallel-only nondeterminism in driver._run_batch. It admitted futures via concurrent.futures.as_completed -\u003e completion order varies run-to-run, and admit() is order-sensitive (accrues n_evals per result; keeps the FIRST individual of an equal-key tie as best). A long parallel run diverged 167 vs 161 fails (maple seed 0) — the real source of the +-3..6 'noise'. FIX: iterate the futures list in SUBMISSION order (block on each f.result() in turn; all still run concurrently), reproducing the serial admission sequence. After fix: two workers=4 runs are byte-identical (162 fails, identical .dom). 211 tests pass.\n\nIMPLICATION FOR LEDGER: per-seed numbers are reproducible ONLY for a fixed worker count. Serial != parallel is EXPECTED (children-per-iteration = 1 vs n_workers changes batch granularity, hence the search), not nondeterminism. Any ledger A/B comparing runs at DIFFERENT worker counts (or pre-fix parallel) conflated this with a real effect — re-run sub-+-3 effects at a fixed worker count.","status":"closed","priority":2,"issue_type":"bug","owner":"bruno@postle.net","created_at":"2026-06-21T20:39:09Z","created_by":"Bruno Postle","updated_at":"2026-06-22T22:13:17Z","closed_at":"2026-06-22T22:13:17Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-9gp.2","title":"M3 Wong-Liu re-association reachability move","description":"9gp.2: add mutate_reassociate, the associativity move (a|b)|c \u003c-\u003e a|(b|c) (same-axis tree rotation on owned/live cuts) missing from the swap(M1)/rotate(M2) set. Targets the §11.4/§11.5 reachability bottleneck. Round-trip/invariant tests. MEASURE value on maple-court vs leu.2 baseline — either result is a valid verdict per the re-scoped bead. DESIGN.md §12.3.","notes":"MEASURED — NEGATIVE (DESIGN.md §12.3). M3 reassociate landed + A/B'd: maple 136.0→139.3, harbor 74.0→78.0 (neutral-to-worse, never a win) across seeds 0/1/2. Reaches new tree shapes but they are not better — third independent negative on search machinery (§11.4/§11.5/§12.3). Kept default-OFF. Valid verdict per re-scope.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-20T16:54:07Z","created_by":"Bruno Postle","updated_at":"2026-06-21T06:20:43Z","started_at":"2026-06-20T17:54:15Z","closed_at":"2026-06-21T06:20:43Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-9gp.2","depends_on_id":"homemaker-py-9gp","type":"parent-child","created_at":"2026-06-20T17:54:07Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-9gp.2","title":"M3 Wong-Liu re-association reachability move","description":"9gp.2: add mutate_reassociate, the associativity move (a|b)|c \u003c-\u003e a|(b|c) (same-axis tree rotation on owned/live cuts) missing from the swap(M1)/rotate(M2) set. Targets the §11.4/§11.5 reachability bottleneck. Round-trip/invariant tests. MEASURE value on maple-court vs leu.2 baseline — either result is a valid verdict per the re-scoped bead. DESIGN.md §12.3.","notes":"MEASURED — NEGATIVE (DESIGN.md §12.3). M3 reassociate landed + A/B'd: maple 136.0→139.3, harbor 74.0→78.0 (neutral-to-worse, never a win) across seeds 0/1/2. Reaches new tree shapes but they are not better — third independent negative on search machinery (§11.4/§11.5/§12.3). Kept default-OFF. Valid verdict per re-scope.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-20T16:54:07Z","created_by":"Bruno Postle","updated_at":"2026-06-21T06:20:43Z","started_at":"2026-06-20T17:54:15Z","closed_at":"2026-06-21T06:20:43Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-9gp.2","depends_on_id":"homemaker-py-9gp","type":"parent-child","created_at":"2026-06-20T17:54:07Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-9gp.1","title":"Shape-feasibility pre-filter before inner loop","description":"9gp.1: predict per-leaf shape fails (size/width/proportion/crinkliness) at the proportion-aware target geometry, prune clearly-infeasible topologies before the inner loop so budget flows to feasible ones. Reuse operators._size_divisions_from_targets + fitness quality methods. Default OFF; threshold is a measured parameter. Hook in driver._evaluate. Measure on maple-court + harbor vs leu.2 baseline. DESIGN.md §12.3.","notes":"MEASURED — NEGATIVE (DESIGN.md §12.3). Shape-feasibility filter landed + A/B'd: maple 136.0→140.0, harbor 74.0→77.0. Filter DID prune/explore more topologies in several runs, but extra topologies didn't lower fails. Calibration: shape floor ≈ achieved total (geometry-bound residual, confirms §11.7), so no lower-fail basin for saved budget to find. Kept default-OFF.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-20T16:53:48Z","created_by":"Bruno Postle","updated_at":"2026-06-21T06:20:41Z","started_at":"2026-06-20T16:54:15Z","closed_at":"2026-06-21T06:20:41Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-9gp.1","depends_on_id":"homemaker-py-9gp","type":"parent-child","created_at":"2026-06-20T17:53:48Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-9gp.1","title":"Shape-feasibility pre-filter before inner loop","description":"9gp.1: predict per-leaf shape fails (size/width/proportion/crinkliness) at the proportion-aware target geometry, prune clearly-infeasible topologies before the inner loop so budget flows to feasible ones. Reuse operators._size_divisions_from_targets + fitness quality methods. Default OFF; threshold is a measured parameter. Hook in driver._evaluate. Measure on maple-court + harbor vs leu.2 baseline. DESIGN.md §12.3.","notes":"MEASURED — NEGATIVE (DESIGN.md §12.3). Shape-feasibility filter landed + A/B'd: maple 136.0→140.0, harbor 74.0→77.0. Filter DID prune/explore more topologies in several runs, but extra topologies didn't lower fails. Calibration: shape floor ≈ achieved total (geometry-bound residual, confirms §11.7), so no lower-fail basin for saved budget to find. Kept default-OFF.","status":"closed","priority":2,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-20T16:53:48Z","created_by":"Bruno Postle","updated_at":"2026-06-21T06:20:41Z","started_at":"2026-06-20T16:54:15Z","closed_at":"2026-06-21T06:20:41Z","close_reason":"Closed","dependencies":[{"issue_id":"homemaker-py-9gp.1","depends_on_id":"homemaker-py-9gp","type":"parent-child","created_at":"2026-06-20T17:53:48Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
|
|
@ -49,8 +50,8 @@
|
||||||
{"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-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 (6–7 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-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 (6–7 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-jrb","title":"Bakeoff: repair operator vs baseline on harbor-house","description":"Bake off the failure-directed repair operator against the current baseline on examples/harbor-house (3m.dom config). Seed from the 3M best (3m.dom) and run ~200k evals, multiple seeds. Also sweep child_budget DOWN (e.g. 80 -\u003e 40 -\u003e 20) to test the hypothesis that reallocating evals from ratio-polishing to topology repair lowers fails. Metric: final n_fails and crinkliness/connected/access counts. Reuse experiments/bakeoff_harbor.py pattern.","status":"open","priority":3,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-23T20:40:21Z","created_by":"Bruno Postle","updated_at":"2026-06-23T20:49:55Z","dependencies":[{"issue_id":"homemaker-py-jrb","depends_on_id":"homemaker-py-71d","type":"parent-child","created_at":"2026-06-23T21:49:55Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-jrb","depends_on_id":"homemaker-py-u8x","type":"blocks","created_at":"2026-06-23T21:40:35Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-jrb","title":"Bakeoff: repair operator vs baseline on harbor-house","description":"Bake off the failure-directed repair operator against the current baseline on examples/harbor-house (3m.dom config). Seed from the 3M best (3m.dom) and run ~200k evals, multiple seeds. Also sweep child_budget DOWN (e.g. 80 -\u003e 40 -\u003e 20) to test the hypothesis that reallocating evals from ratio-polishing to topology repair lowers fails. Metric: final n_fails and crinkliness/connected/access counts. Reuse experiments/bakeoff_harbor.py pattern.","status":"open","priority":3,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-23T20:40:21Z","created_by":"Bruno Postle","updated_at":"2026-06-23T20:49:55Z","dependencies":[{"issue_id":"homemaker-py-jrb","depends_on_id":"homemaker-py-71d","type":"parent-child","created_at":"2026-06-23T21:49:55Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-jrb","depends_on_id":"homemaker-py-u8x","type":"blocks","created_at":"2026-06-23T21:40:35Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-u8x","title":"mutate_repair: failure-directed topology repairs","description":"New operator mutate_repair(parent_root, fails, reqs, rng) in operators.py dispatching on failure class, targeting the leaf id named in each fail string. Priority order = ratio-invariant fails first:\n- crinkliness on L -\u003e retype a geometric neighbour of L to O (interior light well) or reassociate/swap L toward facade (attacks 13)\n- 'level N not connected' -\u003e retype a bridging leaf to C to join circulation components (attacks 2)\n- access on L -\u003e retype a neighbour to C (attacks 1)\n- too few stairs -\u003e core_divide to add aligned vertical core (attacks 1)\nReuse leaf-adjacency graph from _assign_adjacency_aware, plus reassociate/core_divide/retype. Wire into operators.mutate weighting and the driver child-generation path (driver.py:452). Depends on fails being available (parent thread task).","status":"open","priority":3,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-23T20:40:18Z","created_by":"Bruno Postle","updated_at":"2026-06-23T20:49:53Z","dependencies":[{"issue_id":"homemaker-py-u8x","depends_on_id":"homemaker-py-71d","type":"parent-child","created_at":"2026-06-23T21:49:53Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-u8x","depends_on_id":"homemaker-py-7u5","type":"blocks","created_at":"2026-06-23T21:40:33Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
|
{"id":"homemaker-py-u8x","title":"mutate_repair: failure-directed topology repairs","description":"New operator mutate_repair(parent_root, fails, reqs, rng) in operators.py dispatching on failure class, targeting the leaf id named in each fail string. Priority order = ratio-invariant fails first:\n- crinkliness on L -\u003e retype a geometric neighbour of L to O (interior light well) or reassociate/swap L toward facade (attacks 13)\n- 'level N not connected' -\u003e retype a bridging leaf to C to join circulation components (attacks 2)\n- access on L -\u003e retype a neighbour to C (attacks 1)\n- too few stairs -\u003e core_divide to add aligned vertical core (attacks 1)\nReuse leaf-adjacency graph from _assign_adjacency_aware, plus reassociate/core_divide/retype. Wire into operators.mutate weighting and the driver child-generation path (driver.py:452). Depends on fails being available (parent thread task).","status":"closed","priority":3,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-23T20:40:18Z","created_by":"Bruno Postle","updated_at":"2026-06-28T13:21:55Z","closed_at":"2026-06-28T13:21:55Z","close_reason":"Superseded by construction (DESIGN §13.7): interior-O (default-ON, erc.8) is 71d's named fix (interior O courtyards) and collapsed landlocked crinkliness ~13-\u003e2 of 20 in the high-budget probe. Residual now diffuse, no concentrated ratio-invariant block for a targeted repair operator. Reopen/refile if a future floor probe shows a concentrated ratio-invariant class return.","dependencies":[{"issue_id":"homemaker-py-u8x","depends_on_id":"homemaker-py-71d","type":"parent-child","created_at":"2026-06-23T21:49:53Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-u8x","depends_on_id":"homemaker-py-7u5","type":"blocks","created_at":"2026-06-23T21:40:33Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
|
||||||
{"id":"homemaker-py-71d","title":"Failure-directed topology-repair operator (harbor-house plateau)","description":"harbor-house plateaus at 27 fails under a 3M-eval run. Fail breakdown of the 3M best (3m.dom): 13 crinkliness, 7 size, 2 edge-too-long, 2 level-not-connected, 1 proportion, 1 access, 1 too-few-stairs.\n\nDiagnosis: ~16 of 27 fails (crinkliness 13, not-connected 2, access 1, stairs 1... actually 17 incl stairs) are INVARIANT to split ratios, but the inner loop (child_budget=80 CMA evals/child) spends essentially all eval budget on ratios. The outer comparator only keeps n_fails (driver.py:259) and operators pick targets at random, so the search reaches these discrete adjacency/daylight fails only by luck.\n\nCrinkliness root cause: a landlocked leaf (no facade edge, no adjacent uncovered O) has area_outside=0 -\u003e crink=0 -\u003e quality_uncrinkliness hits the 'if not crink: return 0.0' branch (fitness.py:339) -\u003e guaranteed fail for ALL ratios. Big rooms (cr1 80m2, da1 60m2, n 60m2) are worst. Fix is interior O courtyards / facade access = TOPOLOGY only.\n\nPlan: read the parent's structured .fails (already computed at driver.py:146, just not stored on Individual) and apply targeted, mostly-deterministic topology repairs per failure class, attacking the ratio-invariant fails the inner loop cannot touch. Reuses reassociate, core_divide, retype, and the leaf-adjacency graph.","notes":"Reparented under erc (Phase 8) as a Tier-3 search-machinery bet, LOW prior per erc's thesis ('search machinery cannot help — the floor IS the result', 0/3 wins from grade/niching/feasibility). Honest framing: this is NOT refuted by that scoreboard — those 3 losses were all selection/pruning changes; none added a TARGETED REPAIR OPERATOR, which is a new class. But do not invest here until a construction lever (erc.3/.4/ld2) moves the floor. Must follow erc's shared protocol: A/B maple-court + harbor seeds 0/1/2, 20k evals staged, control reproduces baseline (maple 136.0, harbor 74.0), verdict in DESIGN.md §13.x.","status":"open","priority":3,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-23T20:39:34Z","created_by":"Bruno Postle","updated_at":"2026-06-23T20:50:23Z","dependencies":[{"issue_id":"homemaker-py-71d","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-23T21:49:50Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-71d","title":"Failure-directed topology-repair operator (harbor-house plateau)","description":"harbor-house plateaus at 27 fails under a 3M-eval run. Fail breakdown of the 3M best (3m.dom): 13 crinkliness, 7 size, 2 edge-too-long, 2 level-not-connected, 1 proportion, 1 access, 1 too-few-stairs.\n\nDiagnosis: ~16 of 27 fails (crinkliness 13, not-connected 2, access 1, stairs 1... actually 17 incl stairs) are INVARIANT to split ratios, but the inner loop (child_budget=80 CMA evals/child) spends essentially all eval budget on ratios. The outer comparator only keeps n_fails (driver.py:259) and operators pick targets at random, so the search reaches these discrete adjacency/daylight fails only by luck.\n\nCrinkliness root cause: a landlocked leaf (no facade edge, no adjacent uncovered O) has area_outside=0 -\u003e crink=0 -\u003e quality_uncrinkliness hits the 'if not crink: return 0.0' branch (fitness.py:339) -\u003e guaranteed fail for ALL ratios. Big rooms (cr1 80m2, da1 60m2, n 60m2) are worst. Fix is interior O courtyards / facade access = TOPOLOGY only.\n\nPlan: read the parent's structured .fails (already computed at driver.py:146, just not stored on Individual) and apply targeted, mostly-deterministic topology repairs per failure class, attacking the ratio-invariant fails the inner loop cannot touch. Reuses reassociate, core_divide, retype, and the leaf-adjacency graph.","notes":"Reparented under erc (Phase 8) as a Tier-3 search-machinery bet, LOW prior per erc's thesis ('search machinery cannot help — the floor IS the result', 0/3 wins from grade/niching/feasibility). Honest framing: this is NOT refuted by that scoreboard — those 3 losses were all selection/pruning changes; none added a TARGETED REPAIR OPERATOR, which is a new class. But do not invest here until a construction lever (erc.3/.4/ld2) moves the floor. Must follow erc's shared protocol: A/B maple-court + harbor seeds 0/1/2, 20k evals staged, control reproduces baseline (maple 136.0, harbor 74.0), verdict in DESIGN.md §13.x.","status":"closed","priority":3,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-23T20:39:34Z","created_by":"Bruno Postle","updated_at":"2026-06-28T13:21:46Z","closed_at":"2026-06-28T13:21:46Z","close_reason":"Superseded by construction (DESIGN §13.7): interior-O (default-ON, erc.8) is 71d's named fix (interior O courtyards) and collapsed landlocked crinkliness ~13-\u003e2 of 20 in the high-budget probe. Residual now diffuse, no concentrated ratio-invariant block for a targeted repair operator. Reopen/refile if a future floor probe shows a concentrated ratio-invariant class return.","dependencies":[{"issue_id":"homemaker-py-71d","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-23T21:49:50Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-psk","title":"Experiment: island model — prime population from N independent seeds, crossover-heavy migration phase","description":"User-proposed lever (2026-06-23): the Perl Urb workflow ran the search many times and kept the best because runs settled into different local minima. The Python tool is deterministic per --seed, so the analog is: run N independent seeds (e.g. 16), then PRIME a fresh population with those N converged elites and run a second, crossover-heavy phase — an island model with synchronous migration.\n\nKEY DISTINCTION from prior negatives: this is NOT the §11.5 (c4c.5) niching/restart experiment. Those injected FRESH constructive/random seeds for raw diversity and landed null. Here the migrants are FULLY-CONVERGED elites (each spent a complete budget), so they are high-quality building blocks, not diversity filler. The §11.5 'diversity does not help' result does not directly refute this; the mechanism is different (recombination of converged basins, not exploration).\n\nHONEST PRIOR (against): this is a SEARCH-MACHINERY bet, and the leu/c4c epics are decisive that search machinery keeps landing neutral-to-negative (§11.4 graded objective, §11.5 niching+restarts, §9gp M3 reachability + shape-feasibility filter = 3 search-machinery negatives) while CONSTRUCTION/SEED quality wins (§11.6 adjacency-aware seeding, §11.7 adjacency-aware lift = 4 construction wins). The residual is diagnosed as geometry/shape-bound (size/proportion/crinkliness), not population-management-bound. So baseline expectation is neutral.\n\nWHY IT MIGHT STILL PAY: the one untested sub-mechanism is whether crossover can stack wins across independent basins (run A solved cluster X, run B solved cluster Y, child inherits both -\u003e lower total fails than either parent). That has never been tested with converged migrants.","design":"Control / baseline: 'best-of-N' — run N=16 seeds, take the single lowest-fail/highest-fitness result. This is essentially free (the N runs happen anyway) and is the legitimate descendant of Urb's multi-run habit. The experiment must BEAT best-of-N to count, on equal TOTAL budget (N short runs + migration phase vs N+ longer independent runs).\n\nPhase A: run search() for seeds 0..N-1 at a per-seed budget, collect each result.best.root (.dom).\nPhase B: prime a population from those N elites and continue evolving with high p_crossover (e.g. 0.5-0.8) to stress recombination. Reuse existing machinery — no new representation:\n - The seed_factory / bootstrap path in driver.search already accepts a custom seed producer; a factory that cycles through the N pre-evolved roots primes the population directly (no fresh construction).\n - Set bootstrap=True so the N elites are evaluated as the initial population, then the memetic loop runs.\n\nALIGNMENT RISK to measure, not assume: operators.crossover (operators.py:1001) is AREA-MATCHED subtree exchange — it pairs a region of A with the area-closest third of B, with no notion of programmatic/spatial role. Two independently-evolved trees encode similar arrangements with different tree structures (the encoding is not canonical — 9gp closed-negative, abandoned), so the same functional cluster sits at a different path/area/orientation per run. Area-matched splice across independent optima may therefore be disruptive rather than synthesizing, and the inner loop re-solves ratios at the splice boundary (spliced quality not preserved). Instrument: track whether any migration child ever beats max(parent fails) reduction; if crossover children are never net-positive, the null is mechanistic (alignment), not budget.\n\nBenchmarks: maple-court + harbor seeds (the §12.x A/B set), so controls reproduce documented baselines (maple 136.0, harbor 74.0). Record in DESIGN.md (new §12.x) per project convention.\n\nNOT gated on canonical encoding: 9gp is CLOSED with a negative verdict (associativity/reachability tested directly, did not pay). Do not revive the Polish rewrite as a prerequisite.","status":"open","priority":3,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-22T23:06:30Z","created_by":"Bruno Postle","updated_at":"2026-06-22T23:06:30Z","dependencies":[{"issue_id":"homemaker-py-psk","depends_on_id":"homemaker-py-6zy","type":"related","created_at":"2026-06-23T00:06:59Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-psk","depends_on_id":"homemaker-py-9gp","type":"related","created_at":"2026-06-23T00:07:01Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-psk","depends_on_id":"homemaker-py-c4c.5","type":"related","created_at":"2026-06-23T00:07:02Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-psk","title":"Experiment: island model — prime population from N independent seeds, crossover-heavy migration phase","description":"User-proposed lever (2026-06-23): the Perl Urb workflow ran the search many times and kept the best because runs settled into different local minima. The Python tool is deterministic per --seed, so the analog is: run N independent seeds (e.g. 16), then PRIME a fresh population with those N converged elites and run a second, crossover-heavy phase — an island model with synchronous migration.\n\nKEY DISTINCTION from prior negatives: this is NOT the §11.5 (c4c.5) niching/restart experiment. Those injected FRESH constructive/random seeds for raw diversity and landed null. Here the migrants are FULLY-CONVERGED elites (each spent a complete budget), so they are high-quality building blocks, not diversity filler. The §11.5 'diversity does not help' result does not directly refute this; the mechanism is different (recombination of converged basins, not exploration).\n\nHONEST PRIOR (against): this is a SEARCH-MACHINERY bet, and the leu/c4c epics are decisive that search machinery keeps landing neutral-to-negative (§11.4 graded objective, §11.5 niching+restarts, §9gp M3 reachability + shape-feasibility filter = 3 search-machinery negatives) while CONSTRUCTION/SEED quality wins (§11.6 adjacency-aware seeding, §11.7 adjacency-aware lift = 4 construction wins). The residual is diagnosed as geometry/shape-bound (size/proportion/crinkliness), not population-management-bound. So baseline expectation is neutral.\n\nWHY IT MIGHT STILL PAY: the one untested sub-mechanism is whether crossover can stack wins across independent basins (run A solved cluster X, run B solved cluster Y, child inherits both -\u003e lower total fails than either parent). That has never been tested with converged migrants.","design":"Control / baseline: 'best-of-N' — run N=16 seeds, take the single lowest-fail/highest-fitness result. This is essentially free (the N runs happen anyway) and is the legitimate descendant of Urb's multi-run habit. The experiment must BEAT best-of-N to count, on equal TOTAL budget (N short runs + migration phase vs N+ longer independent runs).\n\nPhase A: run search() for seeds 0..N-1 at a per-seed budget, collect each result.best.root (.dom).\nPhase B: prime a population from those N elites and continue evolving with high p_crossover (e.g. 0.5-0.8) to stress recombination. Reuse existing machinery — no new representation:\n - The seed_factory / bootstrap path in driver.search already accepts a custom seed producer; a factory that cycles through the N pre-evolved roots primes the population directly (no fresh construction).\n - Set bootstrap=True so the N elites are evaluated as the initial population, then the memetic loop runs.\n\nALIGNMENT RISK to measure, not assume: operators.crossover (operators.py:1001) is AREA-MATCHED subtree exchange — it pairs a region of A with the area-closest third of B, with no notion of programmatic/spatial role. Two independently-evolved trees encode similar arrangements with different tree structures (the encoding is not canonical — 9gp closed-negative, abandoned), so the same functional cluster sits at a different path/area/orientation per run. Area-matched splice across independent optima may therefore be disruptive rather than synthesizing, and the inner loop re-solves ratios at the splice boundary (spliced quality not preserved). Instrument: track whether any migration child ever beats max(parent fails) reduction; if crossover children are never net-positive, the null is mechanistic (alignment), not budget.\n\nBenchmarks: maple-court + harbor seeds (the §12.x A/B set), so controls reproduce documented baselines (maple 136.0, harbor 74.0). Record in DESIGN.md (new §12.x) per project convention.\n\nNOT gated on canonical encoding: 9gp is CLOSED with a negative verdict (associativity/reachability tested directly, did not pay). Do not revive the Polish rewrite as a prerequisite.","status":"open","priority":3,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-22T23:06:30Z","created_by":"Bruno Postle","updated_at":"2026-06-22T23:06:30Z","dependencies":[{"issue_id":"homemaker-py-psk","depends_on_id":"homemaker-py-6zy","type":"related","created_at":"2026-06-23T00:06:59Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-psk","depends_on_id":"homemaker-py-9gp","type":"related","created_at":"2026-06-23T00:07:01Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-psk","depends_on_id":"homemaker-py-c4c.5","type":"related","created_at":"2026-06-23T00:07:02Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-6zy","title":"Experiment: topology diversity x scaled tournament pressure (joint A/B)","description":"Open lever left untested by §11.5 (homemaker-py-c4c.5): structural niching was A/B'd against the legacy fitness-scalar dedup with selection pressure HELD FIXED at a binary tournament (k=2). §11.5's own mechanism note says maximal diversity under fixed pressure just diffuses effort — i.e. diversity and pressure are coupled and were never co-tuned. This issue isolates that coupling: sweep tournament size jointly with niching to test whether sharper selection converts the extra structural diversity into lower fails, rather than diffusing it. Premise from §11.5 is a diagnosis, not a tested result; the project pivoted to the canonical encoding (homemaker-py-9gp) instead. Tracking so the lever is not silently lost.","design":"§11.5 raised structural diversity to 16/16 but held selection pressure FIXED at a\nbinary tournament (driver._tournament, k=2, driver.py:154; never overridden, no\nsearch() parameter, no env var). The §11.5 writeup names the coupling as the\nmechanism behind its own null result: \"Maximal diversity (16/16) with the fixed\ntournament pressure just diffuses effort — the fitness-scalar dedup's smaller\neffective population exploits a basin slightly harder.\" That is, diversity and\npressure were varied as if independent when they are coupled: niching widens the\npopulation, but k=2 was never sharpened to convert the extra exploration back into\nexploitation.\n\nImplementation:\n- Expose tournament size as a parameter: add `tournament_k: int = 2` to search()\n (and search_staged()), thread it into both _tournament call sites\n (driver.py:448 crossover pair, :452 mutation parent). Optionally an env knob\n HOMEMAKER_TOURNAMENT_K mirroring HOMEMAKER_POP for the experiments harness.\n- Reuse the existing genome.signature / niche_by_signature machinery from c4c.5\n unchanged — this issue adds ONLY the pressure knob and the joint A/B.\n\nA/B design (equal native-fitness budget, URB_NO_OCCLUSION=1, 20000 evals):\n- Grid: niche_by_signature ∈ {off, on} × tournament_k ∈ {2, 3, 4}.\n- The (niche=off, k=2) cell is the legacy baseline; (niche=on, k=2) reproduces\n §11.5's \"niche\" column. New cells are the higher-pressure rows.\n- Seeds: programme-house seeds 0/1/2 (reuse §11.5 seeds for direct comparison),\n plus harbor-house staged seed 0. NOTE the §11.5 sample (3+1 seeds) was thin and\n its null sits within seed noise — widen to \u003e=5 programme-house seeds so a real\n effect is distinguishable from noise this time.\n- Reuse experiments/run_search_scaled.py (NICHE env already wired) +\n run_staged_search.py for harbor; add the k knob to both.\n- Report total fails at budget per cell (primary), plus final-pop distinct\n signatures and distinct-seen (confirm niching still bites at higher k).\n","acceptance_criteria":"On blank-slate programme-house at equal native-fitness budget (\u003e=5 seeds), some (niche, k) cell beats the legacy (off, k=2) baseline mean fails by more than seed noise; OR the joint sweep confirms the §11.5 null is robust to selection pressure (no k recovers a win from 16/16 diversity). Either outcome recorded as a DESIGN.md §11.x subsection + bead notes, with the per-cell fails table. Negative result is an acceptable close.","notes":"Diagnosed during a session reviewing §11.5. Tournament pressure is hard-coded k=2 (driver.py:154); confirmed no override anywhere in src/ or experiments/, no env var, no prior issue. Cheap to run: niche machinery already exists (c4c.5, default-off), only the tournament_k knob is new. Lower priority because §11.5 + §11.4 both concluded the plateau is a reachability (encoding/operator) problem, so this is a loose-end falsification check rather than the expected lever.","status":"open","priority":3,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-22T22:52:28Z","created_by":"Bruno Postle","updated_at":"2026-06-22T22:52:28Z","dependencies":[{"issue_id":"homemaker-py-6zy","depends_on_id":"homemaker-py-9gp","type":"related","created_at":"2026-06-22T23:53:06Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-6zy","depends_on_id":"homemaker-py-c4c.5","type":"related","created_at":"2026-06-22T23:53:04Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-6zy","title":"Experiment: topology diversity x scaled tournament pressure (joint A/B)","description":"Open lever left untested by §11.5 (homemaker-py-c4c.5): structural niching was A/B'd against the legacy fitness-scalar dedup with selection pressure HELD FIXED at a binary tournament (k=2). §11.5's own mechanism note says maximal diversity under fixed pressure just diffuses effort — i.e. diversity and pressure are coupled and were never co-tuned. This issue isolates that coupling: sweep tournament size jointly with niching to test whether sharper selection converts the extra structural diversity into lower fails, rather than diffusing it. Premise from §11.5 is a diagnosis, not a tested result; the project pivoted to the canonical encoding (homemaker-py-9gp) instead. Tracking so the lever is not silently lost.","design":"§11.5 raised structural diversity to 16/16 but held selection pressure FIXED at a\nbinary tournament (driver._tournament, k=2, driver.py:154; never overridden, no\nsearch() parameter, no env var). The §11.5 writeup names the coupling as the\nmechanism behind its own null result: \"Maximal diversity (16/16) with the fixed\ntournament pressure just diffuses effort — the fitness-scalar dedup's smaller\neffective population exploits a basin slightly harder.\" That is, diversity and\npressure were varied as if independent when they are coupled: niching widens the\npopulation, but k=2 was never sharpened to convert the extra exploration back into\nexploitation.\n\nImplementation:\n- Expose tournament size as a parameter: add `tournament_k: int = 2` to search()\n (and search_staged()), thread it into both _tournament call sites\n (driver.py:448 crossover pair, :452 mutation parent). Optionally an env knob\n HOMEMAKER_TOURNAMENT_K mirroring HOMEMAKER_POP for the experiments harness.\n- Reuse the existing genome.signature / niche_by_signature machinery from c4c.5\n unchanged — this issue adds ONLY the pressure knob and the joint A/B.\n\nA/B design (equal native-fitness budget, URB_NO_OCCLUSION=1, 20000 evals):\n- Grid: niche_by_signature ∈ {off, on} × tournament_k ∈ {2, 3, 4}.\n- The (niche=off, k=2) cell is the legacy baseline; (niche=on, k=2) reproduces\n §11.5's \"niche\" column. New cells are the higher-pressure rows.\n- Seeds: programme-house seeds 0/1/2 (reuse §11.5 seeds for direct comparison),\n plus harbor-house staged seed 0. NOTE the §11.5 sample (3+1 seeds) was thin and\n its null sits within seed noise — widen to \u003e=5 programme-house seeds so a real\n effect is distinguishable from noise this time.\n- Reuse experiments/run_search_scaled.py (NICHE env already wired) +\n run_staged_search.py for harbor; add the k knob to both.\n- Report total fails at budget per cell (primary), plus final-pop distinct\n signatures and distinct-seen (confirm niching still bites at higher k).\n","acceptance_criteria":"On blank-slate programme-house at equal native-fitness budget (\u003e=5 seeds), some (niche, k) cell beats the legacy (off, k=2) baseline mean fails by more than seed noise; OR the joint sweep confirms the §11.5 null is robust to selection pressure (no k recovers a win from 16/16 diversity). Either outcome recorded as a DESIGN.md §11.x subsection + bead notes, with the per-cell fails table. Negative result is an acceptable close.","notes":"Diagnosed during a session reviewing §11.5. Tournament pressure is hard-coded k=2 (driver.py:154); confirmed no override anywhere in src/ or experiments/, no env var, no prior issue. Cheap to run: niche machinery already exists (c4c.5, default-off), only the tournament_k knob is new. Lower priority because §11.5 + §11.4 both concluded the plateau is a reachability (encoding/operator) problem, so this is a loose-end falsification check rather than the expected lever.","status":"open","priority":3,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-22T22:52:28Z","created_by":"Bruno Postle","updated_at":"2026-06-22T22:52:28Z","dependencies":[{"issue_id":"homemaker-py-6zy","depends_on_id":"homemaker-py-9gp","type":"related","created_at":"2026-06-22T23:53:06Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-6zy","depends_on_id":"homemaker-py-c4c.5","type":"related","created_at":"2026-06-22T23:53:04Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-c3g","title":"Construction granularity / leaf-shape lever for the geometry residual","description":"HYPOTHESIS with measured motivation (DESIGN.md §12.3 residual diagnostic), unproven — must be A/B'd vs the §12.2 baseline before adoption (same discipline as §11/§12 levers). Finding: maple-court shape fails are UNIFORM (~68/73 leaves fail), at only 0.44 plot utilisation, dominated by crinkliness (perimeter/area) then size (undersize). So the residual is NOT placement-mismatch (no good leaves to place into) and NOT density/area-bound — it is OVER-GRANULAR construction: 73 small leaves for 52 rooms =\u003e high perimeter/area + below-target sizes. Candidate levers (construction side): fewer/larger leaves, merge or share leaves across same-class rooms, coarser circulation spine, or a granularity that trades adjacency coverage for leaf shape. Cheap first experiment: vary the circulation-per-room ratio and/or a min-leaf-area floor in constructive_topology, measure shape-fail floor (operators.predicted_shape_fails) and end-to-end fails on maple+harbor. Alternative outcome to accept: 52 distinct rooms cannot be well-shaped as 52 leaves at this density (geometry floor of the slicing representation). Files: operators.constructive_topology/_grow_leaves/_assign_adjacency_aware.","notes":"MEASURED — NULL (DESIGN.md §12.4). Cheap raw probe: coarser spine lowers SHAPE floor (maple 135→110, harbor 83→66) but raises access/adj equally → raw TOTAL flat-to-worse; div=3 near the total-floor min. End-to-end A/B (20000 evals, seeds 0/1/2): maple div6 137.0 / div8 134.3 vs baseline 136.0; harbor div6 75.3 vs 74.0 — all within ±1.7, inside the ~±3 noise floor, huge per-seed spread. Coarsening the spine does NOT pay end-to-end (shape gain cancelled by access damage that is not free to repair). Kept circ_divisor=3 default. En route found nondeterminism bug xcy (±3 noise). Residual is the geometry floor of the slicing representation at this density.","status":"closed","priority":3,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-21T19:55:38Z","created_by":"Bruno Postle","updated_at":"2026-06-21T23:49:34Z","started_at":"2026-06-21T19:59:09Z","closed_at":"2026-06-21T23:49:34Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-c3g","title":"Construction granularity / leaf-shape lever for the geometry residual","description":"HYPOTHESIS with measured motivation (DESIGN.md §12.3 residual diagnostic), unproven — must be A/B'd vs the §12.2 baseline before adoption (same discipline as §11/§12 levers). Finding: maple-court shape fails are UNIFORM (~68/73 leaves fail), at only 0.44 plot utilisation, dominated by crinkliness (perimeter/area) then size (undersize). So the residual is NOT placement-mismatch (no good leaves to place into) and NOT density/area-bound — it is OVER-GRANULAR construction: 73 small leaves for 52 rooms =\u003e high perimeter/area + below-target sizes. Candidate levers (construction side): fewer/larger leaves, merge or share leaves across same-class rooms, coarser circulation spine, or a granularity that trades adjacency coverage for leaf shape. Cheap first experiment: vary the circulation-per-room ratio and/or a min-leaf-area floor in constructive_topology, measure shape-fail floor (operators.predicted_shape_fails) and end-to-end fails on maple+harbor. Alternative outcome to accept: 52 distinct rooms cannot be well-shaped as 52 leaves at this density (geometry floor of the slicing representation). Files: operators.constructive_topology/_grow_leaves/_assign_adjacency_aware.","notes":"MEASURED — NULL (DESIGN.md §12.4). Cheap raw probe: coarser spine lowers SHAPE floor (maple 135→110, harbor 83→66) but raises access/adj equally → raw TOTAL flat-to-worse; div=3 near the total-floor min. End-to-end A/B (20000 evals, seeds 0/1/2): maple div6 137.0 / div8 134.3 vs baseline 136.0; harbor div6 75.3 vs 74.0 — all within ±1.7, inside the ~±3 noise floor, huge per-seed spread. Coarsening the spine does NOT pay end-to-end (shape gain cancelled by access damage that is not free to repair). Kept circ_divisor=3 default. En route found nondeterminism bug xcy (±3 noise). Residual is the geometry floor of the slicing representation at this density.","status":"closed","priority":3,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-21T19:55:38Z","created_by":"Bruno Postle","updated_at":"2026-06-21T23:49:34Z","started_at":"2026-06-21T19:59:09Z","closed_at":"2026-06-21T23:49:34Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||||
|
|
@ -67,19 +68,20 @@
|
||||||
{"id":"homemaker-py-erc.6","title":"Experiment: inner-loop slack-expansion objective term","description":"Inner-loop counterpart to plot-fill construction. If Diagnostic B shows the inner loop has room to expand leaves into slack but no objective gradient to do so (the scalar rewards hitting target area but not exceeding it where slack exists), add a term/incentive so the ratio optimiser pushes leaf boundaries out to consume neighbouring slack and satisfy size, rather than parking at target.\n\nCONDITIONAL on Diagnostic B: build this only if B localizes the gap to the inner loop (room to expand, no gradient); if B shows construction targets too-small dims, prefer the plot-fill construction sibling. Must preserve the §5.4 inner-loop cliff / §4.9 lexicographic protection — the term sits where it cannot displace the fail-count ordering. A/B vs §12.2 baseline, seeds 0/1/2, 20000 evals, staged, default-OFF. Record DESIGN.md §13.6.","notes":"DEPRIORITISED by Diagnostic B (§13.2). B shows the inner loop CANNOT repair undersize: the slack is depth-driven maldistribution baked into the frozen topology, and the equal-offset ratio DOF cannot shrink a 14x leaf to feed a starved one without trading into shape fails (0.5^n cliff). Wrong DOF and wrong direction — the blocker is slicing POSITION, not a missing expansion reward. Fix belongs upstream in construction/topology (erc.4 re-scoped, erc.3). Keep as a low-priority follow-up only if a depth-balanced construction still leaves a residual size gradient the inner loop could pick up.","status":"open","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-22T23:16:24Z","created_by":"Bruno Postle","updated_at":"2026-06-23T21:47:05Z","dependencies":[{"issue_id":"homemaker-py-erc.6","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-23T00:16:23Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-erc.6","depends_on_id":"homemaker-py-erc.2","type":"blocks","created_at":"2026-06-23T00:16:47Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-erc.6","title":"Experiment: inner-loop slack-expansion objective term","description":"Inner-loop counterpart to plot-fill construction. If Diagnostic B shows the inner loop has room to expand leaves into slack but no objective gradient to do so (the scalar rewards hitting target area but not exceeding it where slack exists), add a term/incentive so the ratio optimiser pushes leaf boundaries out to consume neighbouring slack and satisfy size, rather than parking at target.\n\nCONDITIONAL on Diagnostic B: build this only if B localizes the gap to the inner loop (room to expand, no gradient); if B shows construction targets too-small dims, prefer the plot-fill construction sibling. Must preserve the §5.4 inner-loop cliff / §4.9 lexicographic protection — the term sits where it cannot displace the fail-count ordering. A/B vs §12.2 baseline, seeds 0/1/2, 20000 evals, staged, default-OFF. Record DESIGN.md §13.6.","notes":"DEPRIORITISED by Diagnostic B (§13.2). B shows the inner loop CANNOT repair undersize: the slack is depth-driven maldistribution baked into the frozen topology, and the equal-offset ratio DOF cannot shrink a 14x leaf to feed a starved one without trading into shape fails (0.5^n cliff). Wrong DOF and wrong direction — the blocker is slicing POSITION, not a missing expansion reward. Fix belongs upstream in construction/topology (erc.4 re-scoped, erc.3). Keep as a low-priority follow-up only if a depth-balanced construction still leaves a residual size gradient the inner loop could pick up.","status":"open","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-22T23:16:24Z","created_by":"Bruno Postle","updated_at":"2026-06-23T21:47:05Z","dependencies":[{"issue_id":"homemaker-py-erc.6","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-23T00:16:23Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-erc.6","depends_on_id":"homemaker-py-erc.2","type":"blocks","created_at":"2026-06-23T00:16:47Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
|
||||||
{"id":"homemaker-py-erc.5","title":"Experiment: compactness-aware cuts (minimize leaf perimeter/area)","description":"Attacks the #1 factor, crinkliness (346) — a per-leaf perimeter/area property DISTINCT from proportion (aspect ratio). Proportion-aware seeding (leu.2) sizes splits but does not bias toward balanced, square-ish subdivision. Add a KD-tree-style 'keep both children compact' cut rule (prefer the cut orientation/position that minimises summed child perimeter/area) in construction.\n\nCONDITIONAL on Diagnostic A: if A shows per-leaf shape-fail is FLAT across densities (floor intrinsic to slicing density), better cuts at the same leaf count will not pay → this should be closed wont-fix in favour of leaf-sharing. Only build if A shows shape-fail RISES with density. A/B vs §12.2 baseline, seeds 0/1/2, 20000 evals, staged, default-OFF. Record DESIGN.md §13.5.","notes":"DEPRIORITISED by erc.1 verdict (§13.1): per-leaf shape-fail flat vs slicing density and cuts already squarest (_size_divisions_from_targets picks squarest rotation) yet still ~1.8 fails/leaf =\u003e little compactness headroom at fixed leaf count. Floor is intrinsic to leaf COUNT, not cut quality. Revisit only if leaf-sharing (erc.3) underdelivers.","status":"open","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-22T23:16:21Z","created_by":"Bruno Postle","updated_at":"2026-06-23T21:00:46Z","dependencies":[{"issue_id":"homemaker-py-erc.5","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-23T00:16:21Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-erc.5","depends_on_id":"homemaker-py-erc.1","type":"blocks","created_at":"2026-06-23T00:16:43Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
|
{"id":"homemaker-py-erc.5","title":"Experiment: compactness-aware cuts (minimize leaf perimeter/area)","description":"Attacks the #1 factor, crinkliness (346) — a per-leaf perimeter/area property DISTINCT from proportion (aspect ratio). Proportion-aware seeding (leu.2) sizes splits but does not bias toward balanced, square-ish subdivision. Add a KD-tree-style 'keep both children compact' cut rule (prefer the cut orientation/position that minimises summed child perimeter/area) in construction.\n\nCONDITIONAL on Diagnostic A: if A shows per-leaf shape-fail is FLAT across densities (floor intrinsic to slicing density), better cuts at the same leaf count will not pay → this should be closed wont-fix in favour of leaf-sharing. Only build if A shows shape-fail RISES with density. A/B vs §12.2 baseline, seeds 0/1/2, 20000 evals, staged, default-OFF. Record DESIGN.md §13.5.","notes":"DEPRIORITISED by erc.1 verdict (§13.1): per-leaf shape-fail flat vs slicing density and cuts already squarest (_size_divisions_from_targets picks squarest rotation) yet still ~1.8 fails/leaf =\u003e little compactness headroom at fixed leaf count. Floor is intrinsic to leaf COUNT, not cut quality. Revisit only if leaf-sharing (erc.3) underdelivers.","status":"open","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-06-22T23:16:21Z","created_by":"Bruno Postle","updated_at":"2026-06-23T21:00:46Z","dependencies":[{"issue_id":"homemaker-py-erc.5","depends_on_id":"homemaker-py-erc","type":"parent-child","created_at":"2026-06-23T00:16:21Z","created_by":"Bruno Postle","metadata":"{}"},{"issue_id":"homemaker-py-erc.5","depends_on_id":"homemaker-py-erc.1","type":"blocks","created_at":"2026-06-23T00:16:43Z","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}
|
{"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":"ld2-13-6-interior-o-seed-diagnostic-all","value":"ld2/§13.6 interior-O seed diagnostic: ALL crinkliness fails in the constructed bal+share seed are UNDER-exposed (crink\u003c0.62, landlocked rooms with no facade + no uncovered-O neighbour) — zero over-exposed sliver fails. So the erc crinkliness residual is genuine under-daylighting, validating the interior light-well premise. Default outside_divisor=6 was too sparse (null: harbor 147-\u003e142, crinkliness even rose). odiv=3 is the seed-optimal joint setting: harbor seed fails 147-\u003e129 (-18), maple 219-\u003e206 (-14), landlocked fails drop, at cost of more leaves (harbor +4, maple +8). Because it ADDS leaves it carries the §13.4 wash-out risk; A/B to convergence pending."}
|
|
||||||
{"_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":"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":"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":"proportion-aware-constructive-seeding-leu-2-12-2","value":"Proportion-aware constructive seeding (leu.2/§12.2): sizing seed cuts from target AREAS only regresses (thin slivers wreck aspect); you must ALSO pick each cut's rotation for child squareness. It is a convergence ACCELERATOR via a deeper local optimum around the constructed topology: wins where that topology is roughly right and budget is scarce (harbor -13%, maple -10% at 20k evals) but DELAYS small programmes where the seed must be restructured by undivide (programme-house regresses at fixed budget, yet reaches the floor given budget - speed, not asymptote). Default-on. Also: n_storeys must honour storey_minimum, not just level: keys (programme-house storey_minimum:2, all rooms level:0 - was seeded 1 storey short; cq1)."}
|
|
||||||
{"_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":"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":"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":"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":"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":"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":"proportion-aware-constructive-seeding-leu-2-12-2","value":"Proportion-aware constructive seeding (leu.2/§12.2): sizing seed cuts from target AREAS only regresses (thin slivers wreck aspect); you must ALSO pick each cut's rotation for child squareness. It is a convergence ACCELERATOR via a deeper local optimum around the constructed topology: wins where that topology is roughly right and budget is scarce (harbor -13%, maple -10% at 20k evals) but DELAYS small programmes where the seed must be restructured by undivide (programme-house regresses at fixed budget, yet reaches the floor given budget - speed, not asymptote). Default-on. Also: n_storeys must honour storey_minimum, not just level: keys (programme-house storey_minimum:2, all rooms level:0 - was seeded 1 storey short; cq1)."}
|
||||||
|
{"_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":"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":"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":"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":"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":"run-to-run-reproducibility-in-homemaker-layout-serial","value":"Run-to-run reproducibility in homemaker-layout: serial search (workers=1) is byte-for-byte deterministic; parallel (workers\u003e1) is now deterministic too AFTER fixing driver._run_batch to admit futures in submission order (was as_completed/completion order, bug xcy). Reproducibility holds only for a FIXED worker count — serial vs parallel differ because children-per-iteration is 1 vs n_workers (different batch granularity), which is expected, not a bug. The constructive seeder was NEVER nondeterministic: _assign_adjacency_aware has unique idx tiebreaks; comparing topologies with Python builtin hash() of the signature STRING is invalid (PYTHONHASHSEED salts str hashing per process) — use a stable hash (sha1) or genome.signature equality."}
|
||||||
|
{"_type":"memory","key":"ld2-13-6-interior-o-seed-diagnostic-all","value":"ld2/§13.6 interior-O seed diagnostic: ALL crinkliness fails in the constructed bal+share seed are UNDER-exposed (crink\u003c0.62, landlocked rooms with no facade + no uncovered-O neighbour) — zero over-exposed sliver fails. So the erc crinkliness residual is genuine under-daylighting, validating the interior light-well premise. Default outside_divisor=6 was too sparse (null: harbor 147-\u003e142, crinkliness even rose). odiv=3 is the seed-optimal joint setting: harbor seed fails 147-\u003e129 (-18), maple 219-\u003e206 (-14), landlocked fails drop, at cost of more leaves (harbor +4, maple +8). Because it ADDS leaves it carries the §13.4 wash-out risk; A/B to convergence pending."}
|
||||||
|
{"_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":"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":"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."}
|
||||||
|
{"_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":"experiment-harness-gotcha-the-leaf-sharing-relaxed-objective","value":"Experiment harness gotcha: the leaf-sharing RELAXED objective (§13.3) is injected ONLY by monkeypatching fitness.load_config in the parent process (run_staged_search.py / probe scripts). This is parent-process-only and does NOT propagate into ProcessPoolExecutor workers (n_workers\u003e1), which re-import fitness fresh and score under the STRICT on-disk patterns.config -\u003e r.n_fails MISMATCH (worker strict vs parent relaxed re-score). ALL §13.x floor runs were therefore SERIAL. Any future PARALLEL leaf-sharing experiment will silently mis-score until leaf_sharing lives on disk/CLI (tracked: homemaker-py-x3b). The parallel driver itself is correct; both paths score via load_config(programme_dir)."}
|
||||||
{"_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":"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":"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":"run-to-run-reproducibility-in-homemaker-layout-serial","value":"Run-to-run reproducibility in homemaker-layout: serial search (workers=1) is byte-for-byte deterministic; parallel (workers\u003e1) is now deterministic too AFTER fixing driver._run_batch to admit futures in submission order (was as_completed/completion order, bug xcy). Reproducibility holds only for a FIXED worker count — serial vs parallel differ because children-per-iteration is 1 vs n_workers (different batch granularity), which is expected, not a bug. The constructive seeder was NEVER nondeterministic: _assign_adjacency_aware has unique idx tiebreaks; comparing topologies with Python builtin hash() of the signature STRING is invalid (PYTHONHASHSEED salts str hashing per process) — use a stable hash (sha1) or genome.signature equality."}
|
|
||||||
{"_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."}
|
|
||||||
{"_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."}
|
|
||||||
|
|
|
||||||
62
DESIGN.md
62
DESIGN.md
|
|
@ -1874,3 +1874,65 @@ and matches the dense-programme target. Follow-up `homemaker-py-*` flips the
|
||||||
default (mirroring `pll` after erc.7). `outside_divisor` left at 3 (seed-optimal
|
default (mirroring `pll` after erc.7). `outside_divisor` left at 3 (seed-optimal
|
||||||
joint); a finer odiv sweep under convergence is low-prior given maple's marginal
|
joint); a finer odiv sweep under convergence is low-prior given maple's marginal
|
||||||
response.
|
response.
|
||||||
|
|
||||||
|
### §13.7 High-budget harbor floor probe — 71d go/no-go (homemaker-py-71d.1)
|
||||||
|
|
||||||
|
The whole Phase-8 construction stack is now default-ON (leaf-sharing factor 3,
|
||||||
|
depth-balanced, interior-O odiv=3, circ_divisor 3, proportion-aware). Cumulative
|
||||||
|
floor vs the §12.2 leu.2 baseline (all under the §13.3 leaf-share-relaxed
|
||||||
|
objective, staged, seeds 0/1/2): **maple 136.0 → 80.3 (−41 %), harbor 74.0 → 34.0
|
||||||
|
(−54 %)** — the entire drop from construction levers, zero from search machinery,
|
||||||
|
exactly the epic's thesis.
|
||||||
|
|
||||||
|
This probe decides **71d** (failure-directed topology-repair operator). 71d's
|
||||||
|
premise: the pre-stack harbor 3M-eval plateau (`3m.dom`, re-scores to 27 fails)
|
||||||
|
is dominated by **13 crinkliness** fails, characterised as **landlocked** rooms
|
||||||
|
(`area_outside == 0` → `crink == 0` → `quality_uncrinkliness` hits the
|
||||||
|
`if not crink: return 0.0` branch, fitness.py:355 → guaranteed fail for ALL
|
||||||
|
ratios), repairable only by topology — *specifically interior O courtyards /
|
||||||
|
facade access*. That fix has since shipped DEFAULT-ON (interior_outside, §13.6),
|
||||||
|
so the premise needs re-measuring on the current stack.
|
||||||
|
|
||||||
|
**Setup** (`experiments/probe_harbor_floor.py`, harbor-house, full default stack,
|
||||||
|
seed 0, **500 000** native evals, staged, SERIAL — the leaf-share relaxed
|
||||||
|
objective is injected by a parent-process `fitness.load_config` monkeypatch that
|
||||||
|
does NOT reach `ProcessPoolExecutor` workers, so every §13.x floor run is serial;
|
||||||
|
see homemaker-py-x3b for the production CLI wiring). The probe re-scores the best
|
||||||
|
and splits each crinkliness fail into **landlocked** (`area_outside == 0`, 71d's
|
||||||
|
ratio-invariant target) vs **under-exposed** (`0 < crink < target`, reachable by
|
||||||
|
ratios/seeding).
|
||||||
|
|
||||||
|
| metric | old 3M plateau (pre-stack) | full default stack, 500k |
|
||||||
|
|--------|---------------------------:|-------------------------:|
|
||||||
|
| total fails | 27 | **20** |
|
||||||
|
| crinkliness | 13 | **4** |
|
||||||
|
| landlocked crinkliness | ~13 | **2** |
|
||||||
|
| top residual class | crinkliness | edge-too-long (6) |
|
||||||
|
|
||||||
|
Final residual histogram (20 fails): 6 edge-too-long, 4 crinkliness, 4 size,
|
||||||
|
2 proportion, 2 width, 2 level-not-connected. Re-score OK (relaxed config
|
||||||
|
consistent end-to-end).
|
||||||
|
|
||||||
|
**VERDICT — NO-GO on 71d as scoped; interior-O already dissolved its target.**
|
||||||
|
The landlocked-crinkliness block 71d was built to repair collapsed from ~13 to
|
||||||
|
**2 of 20** — because interior-O seeding *is* 71d's named fix (interior O
|
||||||
|
courtyards) and now does it by default. Crinkliness is no longer the dominant
|
||||||
|
class; the residual is small and spread across edge-too-long / size / proportion
|
||||||
|
/ width / connected, with **no concentrated ratio-invariant block** for a targeted
|
||||||
|
repair operator to attack. A deterministic repair operator remains a genuine new
|
||||||
|
operator class (not refuted by the §11.4/§11.5/§12.3 search-machinery losses), but
|
||||||
|
its expected value is now low: its highest-leverage target is gone, and what
|
||||||
|
remains is diffuse. Recommendation: close 71d (and prerequisites 7u5/jrb/u8x) as
|
||||||
|
superseded-by-construction; the floor 71d targeted was lowered by interior-O, not
|
||||||
|
by search machinery — consistent with the epic scoreboard. The deprioritised P4
|
||||||
|
levers erc.5 (compactness cuts — Diag A: floor is leaf-count not cut-quality, and
|
||||||
|
leaf-sharing over-delivered) and erc.6 (inner-loop slack — Diag B: wrong DOF)
|
||||||
|
close wont-fix on unmet revisit conditions, completing the epic.
|
||||||
|
|
||||||
|
Caveat (honest): single seed, 500k not 3M, relaxed config vs the old strict
|
||||||
|
standalone 27 — so the 20-vs-27 *total* is not a clean apples-to-apples. The
|
||||||
|
robust signal is the **composition collapse** (crinkliness 13→4, landlocked
|
||||||
|
13→2), which the §13.6 three-seed data corroborates (interior-O reliably cuts
|
||||||
|
harbor landlocked fails). Follow-up observation, not part of this verdict:
|
||||||
|
edge-too-long is now the single largest harbor class (6) — a candidate seed for
|
||||||
|
any future floor work, distinct from the crinkliness regime Phase-8 addressed.
|
||||||
|
|
|
||||||
177
experiments/probe_harbor_floor.py
Normal file
177
experiments/probe_harbor_floor.py
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""High-budget harbor-house floor probe on the CURRENT full default stack
|
||||||
|
(homemaker-py-71d.1).
|
||||||
|
|
||||||
|
Decides 71d (failure-directed repair operator) go/no-go. 71d's premise: the
|
||||||
|
harbor 3M-eval plateau (27 fails, 3m.dom) is dominated by LANDLOCKED crinkliness
|
||||||
|
(leaf area_outside==0 -> crink==0 -> quality_uncrinkliness hits the
|
||||||
|
`if not crink: return 0.0` branch, fitness.py:355 -> guaranteed fail for ALL
|
||||||
|
ratios), fixable only by topology (interior O courtyards). That fix
|
||||||
|
(interior_outside, odiv=3) has since shipped DEFAULT-ON (erc.8, §13.6). So:
|
||||||
|
re-run harbor at high budget on the full default stack and split the residual
|
||||||
|
crinkliness fails into LANDLOCKED (area_outside==0, 71d's target) vs
|
||||||
|
UNDER-EXPOSED (0 < crink < target, reachable by ratios/seeding). If landlocked
|
||||||
|
still dominates -> 71d worth it; if interior-O dissolved it -> 71d redundant.
|
||||||
|
|
||||||
|
Run SERIAL (n_workers=1) — the leaf-share relaxed objective is injected by
|
||||||
|
monkeypatching fitness.load_config, which does NOT propagate into
|
||||||
|
ProcessPoolExecutor workers (they re-import fitness fresh, scoring strict ->
|
||||||
|
fail-count MISMATCH). The whole §13.x ladder was run serial for this reason.
|
||||||
|
URB_NO_OCCLUSION=1 python3 experiments/probe_harbor_floor.py [budget] [seed]
|
||||||
|
Defaults: budget=1_000_000, seed=0. Serial ~84 ev/s => 1M ~ 3.3 h.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from collections import Counter
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||||
|
from homemaker_layout import dom, driver, fitness, geometry # noqa: E402
|
||||||
|
from homemaker_layout import graph as graph_mod # noqa: E402
|
||||||
|
from homemaker_layout import dom as dom_mod # noqa: E402
|
||||||
|
|
||||||
|
REPO = Path(__file__).resolve().parents[1]
|
||||||
|
HARBOR = REPO / "examples" / "harbor-house"
|
||||||
|
|
||||||
|
|
||||||
|
def classify_crinkliness(root, conf, cost):
|
||||||
|
"""For the scored (merged) tree, return per-crinkliness-fail leaf classes.
|
||||||
|
|
||||||
|
Mirrors _evaluate_full Phase-2 graph setup so area_outside matches what the
|
||||||
|
evaluator saw. Returns (fails, classes) where classes maps
|
||||||
|
'level/leafid' -> ('landlocked'|'under-exposed', crink, area_outside, type).
|
||||||
|
"""
|
||||||
|
fit = fitness.Fitness(conf, cost)
|
||||||
|
# score_with_fails merges the tree in place and yields canonical fails
|
||||||
|
score, fails = fit.score_with_fails(copy.deepcopy(root))
|
||||||
|
|
||||||
|
# Re-derive the merged tree + base graphs exactly as the evaluator does,
|
||||||
|
# so area_outside/crinkliness reproduce the scored values.
|
||||||
|
work = copy.deepcopy(root)
|
||||||
|
fit2 = fitness.Fitness(conf, cost)
|
||||||
|
fit2.preprocess_building(work)
|
||||||
|
geometry.clear_cache()
|
||||||
|
dom_mod.merge_divided(work)
|
||||||
|
geometry.clear_cache()
|
||||||
|
door_w = fit2.conf("door_width") or 1.2
|
||||||
|
graph_base = graph_mod.build_graphs(work, door_w)
|
||||||
|
lvls = dom_mod.levels(work)
|
||||||
|
|
||||||
|
leaf_metric = {} # 'level/id' -> (crink, area_outside, type)
|
||||||
|
for li, lvl in enumerate(lvls):
|
||||||
|
G = graph_base[li]
|
||||||
|
groups = geometry.boundary_groups(lvl)
|
||||||
|
for leaf in lvl.leaves():
|
||||||
|
if not dom_mod.is_usable(leaf):
|
||||||
|
continue
|
||||||
|
if dom_mod.is_outside(leaf) and not dom_mod.is_covered(leaf):
|
||||||
|
continue # the O leaves themselves are exempt (quality 1.0)
|
||||||
|
ao = fit2.area_outside(leaf, G, groups)
|
||||||
|
crink = fit2.crinkliness(leaf, G, groups)
|
||||||
|
leaf_metric[f"{li}/{leaf.id}"] = (crink, ao, leaf.type or "")
|
||||||
|
|
||||||
|
classes = {}
|
||||||
|
for f in fails:
|
||||||
|
if not f.endswith(" crinkliness"):
|
||||||
|
continue
|
||||||
|
key = f[: -len(" crinkliness")]
|
||||||
|
crink, ao, ltype = leaf_metric.get(key, (None, None, "?"))
|
||||||
|
if ao is None:
|
||||||
|
cls = "unknown"
|
||||||
|
elif ao <= 1e-9:
|
||||||
|
cls = "landlocked"
|
||||||
|
else:
|
||||||
|
cls = "under-exposed"
|
||||||
|
classes[key] = (cls, crink, ao, ltype)
|
||||||
|
return score, fails, classes
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
budget = int(sys.argv[1]) if len(sys.argv) > 1 else 1_000_000
|
||||||
|
seed = int(sys.argv[2]) if len(sys.argv) > 2 else 0
|
||||||
|
out = REPO / "scratch" / "harbor_floor_probe" / f"harbor_fullstack_s{seed}.dom"
|
||||||
|
out.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
os.environ.setdefault("URB_NO_OCCLUSION", "1")
|
||||||
|
|
||||||
|
# Full default stack, leaf-share config injected into the WHOLE pipeline so
|
||||||
|
# the search and the re-score share one relaxed objective (§13.3), matching
|
||||||
|
# how every §13.x floor number was produced.
|
||||||
|
_orig_load = fitness.load_config
|
||||||
|
|
||||||
|
def _load_with_sharing(directory):
|
||||||
|
conf, cost = _orig_load(directory)
|
||||||
|
conf = dict(conf)
|
||||||
|
conf["leaf_sharing"] = True
|
||||||
|
conf["max_share"] = 3
|
||||||
|
return conf, cost
|
||||||
|
|
||||||
|
fitness.load_config = _load_with_sharing
|
||||||
|
conf, cost = fitness.load_config(HARBOR)
|
||||||
|
|
||||||
|
seed_root = dom.load(str(HARBOR / "init.dom"))
|
||||||
|
print(f"=== harbor floor probe: budget={budget} seed={seed} serial ===",
|
||||||
|
flush=True)
|
||||||
|
print("stack: leaf_sharing(3) + depth_balanced + interior_outside(odiv=3) "
|
||||||
|
"+ circ_divisor=3 + proportion-aware (current defaults)", flush=True)
|
||||||
|
t0 = time.perf_counter()
|
||||||
|
|
||||||
|
r = driver.search_staged(
|
||||||
|
seed_root, HARBOR,
|
||||||
|
budget=budget, pop_size=16, child_budget=80, seed_budget=300,
|
||||||
|
stage1_frac=0.4, base_p=0.15, p_crossover=0.2, seed=seed,
|
||||||
|
log=lambda m: print(m, flush=True),
|
||||||
|
seed_adjacency_aware=True, seed_proportion_aware=True,
|
||||||
|
circ_divisor=3,
|
||||||
|
leaf_sharing=True, leaf_share_factor=3,
|
||||||
|
depth_balanced=True,
|
||||||
|
interior_outside=True, outside_divisor=3,
|
||||||
|
)
|
||||||
|
elapsed = time.perf_counter() - t0
|
||||||
|
print(f"\n--- done in {elapsed:.0f}s ({r.n_evals/elapsed:.1f} ev/s), "
|
||||||
|
f"{r.n_evals} evals across {r.n_topologies} topologies ---", flush=True)
|
||||||
|
print(f"best: {r.best.fitness:.6g} ({r.best.n_fails} fails) via {r.best.lineage}",
|
||||||
|
flush=True)
|
||||||
|
|
||||||
|
dom.dump(r.best.root, str(out))
|
||||||
|
|
||||||
|
score, fails, classes = classify_crinkliness(r.best.root, conf, cost)
|
||||||
|
ok = math.isclose(score, r.best.fitness, rel_tol=1e-9)
|
||||||
|
print(f"\nre-scored: {score:.6g} ({len(fails)} fails) "
|
||||||
|
f"{'OK' if ok else 'MISMATCH'}", flush=True)
|
||||||
|
|
||||||
|
# Fail-type histogram (last token of each fail string).
|
||||||
|
types = Counter(f.split()[-1] if " " in f else f for f in fails)
|
||||||
|
print("\nfail-type histogram:", flush=True)
|
||||||
|
for t, n in types.most_common():
|
||||||
|
print(f" {n:3d} {t}", flush=True)
|
||||||
|
|
||||||
|
# Crinkliness landlocked split — the 71d decision metric.
|
||||||
|
cls_count = Counter(v[0] for v in classes.values())
|
||||||
|
n_crink = len(classes)
|
||||||
|
print(f"\ncrinkliness fails: {n_crink} total", flush=True)
|
||||||
|
for c in ("landlocked", "under-exposed", "unknown"):
|
||||||
|
if cls_count.get(c):
|
||||||
|
print(f" {cls_count[c]:3d} {c}", flush=True)
|
||||||
|
print("\nper-crinkliness-leaf detail (key | class | crink | area_outside | type):",
|
||||||
|
flush=True)
|
||||||
|
for key, (cls, crink, ao, ltype) in sorted(classes.items()):
|
||||||
|
cs = f"{crink:.3f}" if crink is not None else "?"
|
||||||
|
aos = f"{ao:.2f}" if ao is not None else "?"
|
||||||
|
print(f" {key:18s} {cls:13s} crink={cs:>7s} ao={aos:>7s} type={ltype}",
|
||||||
|
flush=True)
|
||||||
|
|
||||||
|
landlocked = cls_count.get("landlocked", 0)
|
||||||
|
print(f"\nVERDICT INPUT: {landlocked}/{n_crink} crinkliness fails are "
|
||||||
|
f"LANDLOCKED (71d's ratio-invariant target); total fails {len(fails)}.",
|
||||||
|
flush=True)
|
||||||
|
return 0 if ok else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Loading…
Add table
Reference in a new issue