Answering "are we clean". Generic namespace: yes. Usage namespace: no.
FINISH §39.4. The first sweep missed sites, found by a full re-grep:
graph.py's free-area budget, operators.py host-preference / keep-type /
repair-candidate, fitness.py's ("l","c","k") public-access test, bubble.py's
generic adjacency reference, and -- the important one -- cpsat.py, which was
still matching adjacency by raw startswith. graph.code_matches_requirement is
now the single public answer to "does this leaf count as the thing the
programme asked to be next to", shared by has_adjacency, has_vertical_connection
and cpsat.
RETRACT §39.5. It concluded 2g7.5's CP-SAT seeder win did not survive the
correction. That was wrong. The cause was the missed cpsat matcher above: the
exact solver was optimising a different relation than the scorer checked, so a
failing test reporting an incomplete sweep was misread as a baseline shift.
Re-measured over 6 seeds, cpsat now wins on both programmes (harbor 102/92,
maple 156/154). xfail removed.
REAL BUG UNDERNEATH: CP-SAT was never deterministic despite
num_search_workers=1 and a comment claiming it. neighbors[slot] is a set of
dom.Node, which hashes by id() -- a memory address -- so raw iteration made the
model-build order vary and CP-SAT returned a different equally-optimal
assignment each run (measured 194/180/171/182 over four identical aggregates).
sorted() on the slot indices fixes it. Also paired the wall-clock cap with
max_deterministic_time (solves run ~124ms against a 2s cap, so nothing was
timing out -- latent hazard, not the cause). solve_room_labels is now
reproducible on every captured instance; constructive_topology on the cpsat
path still is not, filed as homemaker-py-fdp (plausible contributor to b8g).
§39.6 THE SECOND NAMESPACE. Usage prefixes b/t/l/k (bedroom/toilet/living/
kitchen) classify programme codes by first letter and stay prefix-based by
design, but they are not inert: has_circulation deletes graph edges from them.
Four corpus rooms are misclassified by spelling -- la1 "Laundry Room" and li1
"Library Corner" as living, br1 "Staff Room" as bedroom, tr1 "Treatment Room"
as toilet. Measured on a health-centre seed: tr1 loses its edge to the adjacent
O, br1 loses its edge to t10 "Staff WC" -- both feed the connectivity fails §38
found persisting. Filed homemaker-py-sel; an explicit usage: key is the fix,
but it changes fitness for correctly-spelled programmes too so it needs its own
A/B.
DOCS. README gains a "Room codes and reserved names" section; CLAUDE.md and
AGENTS.md gain the same summary for agents. audit_programme_config.py now
reports the usage class each code picks up alongside the namespace and
satisfiability checks. DESIGN §37.2's note calling the c/o/s quirk "existing
product behaviour, not a bug" is annotated as superseded.
Corpus audit: zero generic-namespace violations across all ten example
programmes. 346 passed, same 7 pre-existing fixture failures, lint unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
5.3 KiB
Project Instructions for AI Agents
This file provides instructions and context for AI coding agents working on this project.
Beads Issue Tracker
This project uses bd (beads) for issue tracking. Run bd prime to see full workflow context and commands.
Quick Reference
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --claim # Claim work
bd close <id> # Complete work
Rules
- Use
bdfor ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists - Run
bd primefor detailed command reference and session close protocol - Use
bd rememberfor persistent knowledge — do NOT use MEMORY.md files
Room-code namespaces (DESIGN.md §39.4/§39.6)
Leaf types share a first character across three namespaces:
C/O/S— generic structural types (circulation / outside / sahn), uppercase, reserved. A programme code spelled exactly one of these is rejected at load.- programme room codes — lowercase, may start with any letter. The generic
tests match
C/O/Sexactly, socr1is a room, not circulation. - usage prefixes
b/t/l/k— bedroom / toilet / living / kitchen, still matched by first letter by design.graph.has_circulationstrips graph edges from them, so a code beginning with one inherits that room's connectivity rules whether or not intended (homemaker-py-sel).
When adding or editing a programme, run
python experiments/audit_programme_config.py — it reports reserved-name
collisions, the usage class each code picks up, and per-room-spec satisfiability.
Session Completion
When ending a work session, you MUST complete ALL steps below. Work is NOT complete until git push succeeds.
MANDATORY WORKFLOW:
- File issues for remaining work - Create issues for anything that needs follow-up
- Run quality gates (if code changed) - Tests, linters, builds
- Update issue status - Close finished work, update in-progress items
- PUSH TO REMOTE - This is MANDATORY:
git pull --rebase bd dolt push git push git status # MUST show "up to date with origin" - Clean up - Clear stashes, prune remote branches
- Verify - All changes committed AND pushed
- Hand off - Provide context for next session
CRITICAL RULES:
- Work is NOT complete until
git pushsucceeds - NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds
Build & Test
pip install -e .
pytest
Architecture Overview
homemaker-layout is a Python successor to the Perl Urb project. It represents a building as a binary slicing tree where leaves carry target dimensions from the programme and division ratios are solved bottom-up (inverting Urb's top-down approach). The evolutionary search explores topology, types, and adjacency only.
Key modules:
dom.py— read/write Urb.domYAML into aNodetreegeometry.py— faithful port of Urb's top-down geometryprogramme.py— parsepatterns.configspace requirementssolver.py— bottom-up ratio solve (scipy)shapecurve.py— Otten/Stockmeyer shape-curve DP: exact size/width/proportion feasibility for a frozen topology, any storey count (DESIGN.md §37.2/§37.4-§37.6); used asdriver._evaluate's NM warm-start/hard pre-filtercpsat.py— exact room-code-to-leaf labelling via OR-Tools CP-SAT for a fixed topology (DESIGN.md §37.7); replacesoperators._assign_adjacency_aware's greedy/beam room placement behindassign_solver="cpsat", and powers theoperators.mutate_reassignin-search repair operatorfitness.py— native Python fitness evaluator (replaces Perl oracle)fitness_cmd.py—homemaker-fitnessCLI entry pointcollapse_cmd.py—homemaker-collapseCLI: finish-time global cell→room collapse (94g)graph.py— leaf-adjacency graph for programme-driven fitness checksgenome.py— topology genome: base-floor tree + per-storey deltasoperators.py— high-locality mutation and subtree crossoverinnerloop.py— ratio optimisation inner loop (Nelder-Mead / CMA-ES)driver.py— memetic search outer loopevolve.py—homemaker-evolveCLI entry pointoracle.py— legacy Perl shim, kept for validation only; do not use in new codebubble.py— 3D bubble-diagram adjacency fitness-signal prototype (DESIGN.md §27,mi7); validated NULL, not wired intofitness.py— reference only, do not build on without a new formulation
Conventions & Patterns
Scoring .dom files
Use the native homemaker-fitness command. Like the old urb-fitness.pl, you
must cd to the directory containing the .dom file first — the tool
resolves patterns.config, costs.config, and writes .score/.fails
relative to cwd:
cd /home/bruno/src/homemaker-layout/examples/programme-house
homemaker-fitness cf0b8a77e8b2325f92a7e7d150184a55.dom
The score is written to <file>.dom.score and failures to <file>.dom.fails; the numeric score is also printed to stderr.
Do not use urb-fitness.pl directly — oracle.py and the Perl tool are
kept only for cross-validation.