Commit graph

9 commits

Author SHA1 Message Date
d004e4c937 Phase 6 §11.7: adjacency-aware lift + secondary adjacencies (ld5)
_assign_adjacency_aware gains fixed_circ (seed the connected-dominating-set from
given circulation leaves) and secondary-adjacency-aware room placement: codes
with the most non-c adjacency requirements are placed first, each onto the open
slot satisfying the most of its requirements against already-typed neighbours
(clustering k1<->da1, da1<->o). lift_base_to_storeys(reqs, adjacency_aware=True)
grows the upper-floor circulation spine off the inherited vertical core and
assigns rooms around it; threaded through driver.search_staged
(seed_adjacency_aware) and run_staged_search.py (ADJ env).

End-to-end staged harbor, 20000 evals, mean total fails over 3 seeds:
ADJ=0 99.0 (reproduces the §11.4 staged lex baseline exactly), ADJ=1 85.3
(-13.7, -14%; best 78). New best harbor configuration overall: staged baseline
99.0 -> single-stage adjacency-aware (§11.6) 90.7 -> staged + adjacency-aware
lift 85.3. Staging and adjacency-aware seeding compose.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:47:40 +01:00
c1586237ca Phase 6 §11.6: adjacency-aware constructive seeding (s44)
operators._assign_adjacency_aware spends ~one extra leaf per three rooms on a
greedy connected-dominating-set of circulation leaves (read from the geometric
leaf_graph, type-independent), so every room borders a connected circulation
spine and adjacency-to-c + access are satisfied by construction. Default-on via
constructive_topology(adjacency_aware=True), threaded through
driver.search(seed_adjacency_aware) and run_search_scaled.py (ADJ env).

End-to-end single-stage, 20000 evals, mean total fails over 3 seeds:
harbor 110.0 -> 90.7 (-17.5%; ADJ=0 reproduces the §11.2 105 baseline exactly),
programme-house 12.3 -> 9.3 (-24%). Adjacency-aware single-stage harbor (mean
90.7, best 85) beats the §11.3 staged best of 95 — the first Phase-6 fail-count
reduction from seeding. Follow-ups (lift_base_to_storeys, secondary adjacencies)
filed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 09:23:12 +01:00
6ed9e0b4b1 Phase 6 §11.3: staged per-floor search (c4c.3)
Search the genome in causal dependency order. Stage 1 evolves a single-storey
base over the level-0 room set (programme auto-derived to a tempdir), ranked
with a substrate-readiness bonus (reserved core × divisible capacity) so the
base is selected as a good substrate, not just a good ground floor (anti-§4.2).
Stage 2 lifts the best base into a full multi-storey design — preserving the
inherited core, instantiating each upper storey's required set by construction —
and searches the deltas with the base mutable at low probability (base_p=0.15).

New: programme.{n_storeys_required,partition_rooms_by_storey,write_stage1_programme},
graph.substrate_readiness, operators.{lift_base_to_storeys,_pick_weighted_by_storey},
base_p threading, driver.search rank_bonus_fn/seed_factory/base_p hooks +
search_staged orchestrator, experiments/run_staged_search.py, tests/test_staging.py.

Result (harbor, 20000 evals, seed 0): staged 95 fails vs single-stage 105
(-10, -9.5%), gain in crinkliness 27->18 + edge 12->8. Anti-bungalow confirmed
(Stage-2 core moves all noop — core inherited, not carved). Programme-house
regression PASS (warmstart-2f4 still reaches whole-pop 1-fail).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 06:05:53 +01:00
de60200bbc Phase 6 §11.2: programme-aware construction + missing-room repair (c4c.2)
Make the required programme room set a constructive invariant instead of
something the topology search must stumble onto by random divide+retype.

- operators.constructive_topology: bootstrap seeder that sizes each storey to
  its required rooms (partitioned by level; level-free rooms distributed),
  +1 core C and +1 O per storey, then assigns types. Stochastic for population
  diversity. Wired into driver bootstrap when the programme has required spaces.
- operators.mutate_place_missing: repair op that inserts a missing required
  space by dividing a host leaf into [room | remainder]. Lex-safe host ranking
  (generic O first, never displace a required room); honours required level.
  Weight 2.0 in the mutation mix; noops cheaply once the set is complete.

A/B on harbor-house (20k evals, seed 0, identical config):
  old random-bootstrap 133 fails (103 missing, 77%)
  new constructive     105 fails ( 12 missing, 11%)  -21% total, missing-stack
  collapsed; seed head-start 163->139.
§4.10 regression PASS: warmstart-2f4 still reaches a 1-fail population at 50k.

Verdict (DESIGN.md §11.2): construction is necessary and reframes the
bottleneck to quality-fail packing of a complete dense design (crinkliness/
size/access/edge) -> unblocks §11.3 staging, motivates §11.4 graded objective.
Follow-up filed (homemaker-py-s44): adjacency-aware seeding.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 22:51:58 +01:00
d330a9171c Add mutate_level_compound_fix: escape deceptive level-fix valley
When level_fix alone displaces a required room (e.g. t3) it triggers 5
oracle fails for the missing room — far worse than the starting 2 fails,
so lex always rejects it.  level_compound_fix atomically: moves the
constrained room to its required floor AND re-inserts the displaced room
by splitting the sibling of the largest C leaf on that floor.  The C
sibling is guaranteed adjacent to C (shared parent split), so the
displaced room keeps its required C-adjacency.

On programme-house this jumps the warmstart from 2 fails (l1 wrong
level + t3 size) to 1 fail (staircase volume), which lex accepts as an
improvement and provides a new base for further mutation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 22:46:23 +01:00
191f603440 Add core_divide, core_undivide, level_fix operators; wire reqs to mutate()
core_divide: divides a C leaf simultaneously on ALL storeys that share that
path, maintaining staircase consistency as an atomic invariant rather than
requiring multi-step recovery.

core_undivide: reverses core_divide consistently across all floors, merging
a C sub-core back into a single C leaf everywhere.

level_fix: atomically moves a level-constrained room to its required floor
by retyping the largest leaf there and vacating the wrong-floor leaf to C.
Requires `reqs` (SpaceReq dict); disabled (zero probability) without it.

mutate() gains `reqs=None` parameter; driver.search() passes its already-
loaded reqs so level_fix fires during the main memetic loop.

Together these let the optimiser escape the deceptive valley around the
2-fail warmstart: level_fix moves l1 to level 0 (reducing fails 2→1),
then core_divide can split the C core to accommodate the displaced t3.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 16:10:20 +01:00
507cf82d99 Add mutate_level_retype: swap leaf types between storeys
Cross-storey equivalent of mutate_retype. Directly addresses
level-constraint failures ("l1 on wrong level") by moving a room type
from one floor to another without changing topology or geometry.

Registered in MUTATIONS at default weight (1.0); no drastic geometry
perturbation so it does not need the reduced level_add/delete weight.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 10:52:48 +01:00
517a825505 Fix mutate_level_add: use generic C/O floor instead of room duplicate
Previously level_add copied the top storey exactly, duplicating all
named programme rooms and immediately triggering space-count failures
for every room on the new floor. The lex outer-search comparison
(-n_fails, score) then always rejected the multi-storey child because
its fail count was far higher than the single-storey parent.

Fix: retype all named-room leaves on the new storey to generic C or O
before admitting the child. The outer search then retypes them
incrementally via the normal retype operator. This allows level_add to
produce designs with the same fail count as the parent (storey_minimum
fail removed, no duplication fails added), making the multi-storey
transition visible to the lex selector.

Result on programme-house cold start (init.dom, 100k evals, 4 workers):
  before: 6 fails, single-storey, stuck after 40k evals
  after:  4 fails, two-storey, still improving at 100k

Also adds examples/harbor-house/ from urb/examples for future runs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 10:33:05 +01:00
646ee30ab6 Rename package: homemaker → homemaker-layout
- src/homemaker/ → src/homemaker_layout/; all imports updated
- pyproject.toml: name = homemaker-layout, entry point updated
- .beads/config.yaml: dolt sync.remote updated to homemaker-layout.git
- Delete temporary debug/perl scripts from project root
- README.md, DESIGN.md: package path references updated
- GitHub repo renamed; git remote updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 08:18:06 +01:00
Renamed from src/homemaker/operators.py (Browse further)