Harbor A/Bs at n=3 could never resolve their own margins

0wr asked which harbor A/Bs were decided by a narrow margin before 39.4.
Measuring harbor's variance makes the margin-by-margin triage moot.

Harbor's paired seed-to-seed sd is 6.19 fails (24 paired ON/OFF runs,
budget 2500), so n=3 resolves nothing finer than 15.4 fails. Every recorded
harbor margin is below that: 13.9 share_edge_cap 3.7, 20 qpk 8.3, 23 f1d
mixed, 37.1 tiering 6.3. So it is not that SOME harbor results were narrow
-- no harbor A/B run at three seeds could resolve the margin it reported,
independently of what 39.4 did to the programme. Of the 220 possible
3-seed subsets of the 24 runs, 56 (25%) show a clean 3/3 sweep for ON.

Re-measured 20's harbor arm, the one backing a live default:
  N=3    2W/1L/0T  +2.67  p=0.560
  N=12   8W/3L/1T  +3.50  p=0.076
  N=24  13W/10L/1T +1.21  p=0.502  CI [-2.46,+4.88]

Null. The published "harbor: ON wins 3/3, 80.3 -> 72.0" was a lucky draw --
even seeds 1-3 measured here give 2W/1L, not a sweep.

So 20's claim that the qpk verdict "holds at both example scales tested" is
withdrawn and annotated in place. collapse_insearch's default rests on
programme-house alone (38.19, N=60, +0.57, p=0.017). It is not refuted on
harbor -- direction positive but indistinguishable from zero -- but harbor
must not be cited as corroboration.

Harness generalised (PROG/BUDGET/WORKERS) and results kept.

Filed homemaker-py-... : A/B harnesses should report the minimum detectable
difference for the N they run, so an underpowered verdict is visible when
it is made rather than years later.

Closes homemaker-py-0wr.

Lint at parity (46).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
This commit is contained in:
Claude 2026-08-29 19:34:30 +00:00
parent 57d8391c52
commit caf480aa32
No known key found for this signature in database
4 changed files with 111 additions and 4 deletions

View file

@ -36,13 +36,14 @@
{"_type":"issue","id":"homemaker-py-1p0","title":"Geometry inner loop: full-objective equal-offset ratio optimiser","description":"DESIGN.md §5.1, §7 Phase 1. Productionise experiments/optimize_fullfitness.py into homemaker: optimise(topology, x0=None) -\u003e (geometry, fitness). DOF = equal-offset division ratios of free branches (solver.free_branches, lowest-storey cut ownership), clipped to [eps, 1-eps]. Objective = full oracle fitness (never a proxy — §4.2 falsified). Must support warm-start x0 (§5.6) and a population/batch evaluation mode so each iteration scores via one batched oracle call (§4.6).","acceptance_criteria":"Reproduces or exceeds §4.5 gains (x1.24x1.67, no new failures) on 2f45907, candidate-002, c964435; works as a library call on any corpus .dom","status":"closed","priority":1,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:36:58Z","created_by":"Bruno Postle","updated_at":"2026-06-12T08:46:31Z","started_at":"2026-06-12T00:14:19Z","closed_at":"2026-06-12T08:46:31Z","close_reason":"innerloop.optimise() lands: batched CMA-ES sigma ladder (0.05/0.15, IPOP popsize doubling, deterministic seeding) over equal-offset free-branch ratios vs full oracle fitness; warm-start x0 supported. Acceptance vs unprojected originals: x1.65/x1.66/x1.58 against bars x1.24/x1.67/x1.59, no new failures, 46 oracle calls vs NM's 200. Two near-bar results accepted as reproduced-within-noise (1% tol) — draw spread brackets the single-NM-draw bars; approved by Bruno 2026-06-12. Gotchas: equal-offset projection of legacy unequal cuts loses fitness/adds failures (midpoint projection used); pycma seed=0 means clock-seeded.","dependencies":[{"issue_id":"homemaker-py-1p0","depends_on_id":"homemaker-py-av5","type":"blocks","created_at":"2026-06-12T00:39:33Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":3,"comment_count":0} {"_type":"issue","id":"homemaker-py-1p0","title":"Geometry inner loop: full-objective equal-offset ratio optimiser","description":"DESIGN.md §5.1, §7 Phase 1. Productionise experiments/optimize_fullfitness.py into homemaker: optimise(topology, x0=None) -\u003e (geometry, fitness). DOF = equal-offset division ratios of free branches (solver.free_branches, lowest-storey cut ownership), clipped to [eps, 1-eps]. Objective = full oracle fitness (never a proxy — §4.2 falsified). Must support warm-start x0 (§5.6) and a population/batch evaluation mode so each iteration scores via one batched oracle call (§4.6).","acceptance_criteria":"Reproduces or exceeds §4.5 gains (x1.24x1.67, no new failures) on 2f45907, candidate-002, c964435; works as a library call on any corpus .dom","status":"closed","priority":1,"issue_type":"feature","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:36:58Z","created_by":"Bruno Postle","updated_at":"2026-06-12T08:46:31Z","started_at":"2026-06-12T00:14:19Z","closed_at":"2026-06-12T08:46:31Z","close_reason":"innerloop.optimise() lands: batched CMA-ES sigma ladder (0.05/0.15, IPOP popsize doubling, deterministic seeding) over equal-offset free-branch ratios vs full oracle fitness; warm-start x0 supported. Acceptance vs unprojected originals: x1.65/x1.66/x1.58 against bars x1.24/x1.67/x1.59, no new failures, 46 oracle calls vs NM's 200. Two near-bar results accepted as reproduced-within-noise (1% tol) — draw spread brackets the single-NM-draw bars; approved by Bruno 2026-06-12. Gotchas: equal-offset projection of legacy unequal cuts loses fitness/adds failures (midpoint projection used); pycma seed=0 means clock-seeded.","dependencies":[{"issue_id":"homemaker-py-1p0","depends_on_id":"homemaker-py-av5","type":"blocks","created_at":"2026-06-12T00:39:33Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":3,"comment_count":0}
{"_type":"issue","id":"homemaker-py-8cs","title":"Experiment: warm-vs-cold start of inner loop (Lamarckian inheritance)","description":"DESIGN.md §5.6, §4.6. Warm-starting a child topology's inner loop from the parent's optimised ratios is the main lever for cutting per-topology cost (~3 min/topology cold). Apply single topology mutations to optimised corpus designs, re-optimise warm (surviving cuts keep values, new cuts get heuristic defaults) vs cold, compare oracle-call counts to convergence at equal final fitness.","acceptance_criteria":"Speedup factor measured across \u003e=10 mutated topologies; decision recorded (expect order-of-magnitude; if \u003c2x, revisit §4.6 Phase-2 scoping)","notes":"Experiment script committed (experiments/warm_vs_cold.py, 1cc86c8) and machinery validated oracle-free; one mutated child scored through the oracle OK. Waiting on homemaker-py-gp2 reference run to finish, then execute under URB_NO_OCCLUSION=1 (3 parents x 400 evals + 12 children x 2 x 200 evals, ~1.5-2 h oracle time). Default budgets: parent 400, child 200; target = evals to 95% of best final.","status":"closed","priority":1,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-11T23:36:58Z","created_by":"Bruno Postle","updated_at":"2026-06-12T11:44:45Z","closed_at":"2026-06-12T11:44:45Z","close_reason":"Measured (URB_NO_OCCLUSION=1, parent budget 400, child 200, 12 single mutations across 3 designs): cold start reached 95% of warm final in 0/12 cases within budget — speedup unbounded at practical budgets; warm finals beat cold finals x1.2-x4 in 12/12; 6/12 warm starts were within 95% at 1 eval (near-neutral mutations). Decision: Lamarckian warm-starting is MANDATORY in the memetic driver (homemaker-py-b39), not an optimisation; cold starts produce strictly worse geometry at equal budget. Note: 2 undivides were exactly fitness-neutral (same-type merge == Merge_Divided equivalence) — locality datum for homemaker-py-nyb.","dependencies":[{"issue_id":"homemaker-py-8cs","depends_on_id":"homemaker-py-1p0","type":"blocks","created_at":"2026-06-12T00:39:34Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-8cs","title":"Experiment: warm-vs-cold start of inner loop (Lamarckian inheritance)","description":"DESIGN.md §5.6, §4.6. Warm-starting a child topology's inner loop from the parent's optimised ratios is the main lever for cutting per-topology cost (~3 min/topology cold). Apply single topology mutations to optimised corpus designs, re-optimise warm (surviving cuts keep values, new cuts get heuristic defaults) vs cold, compare oracle-call counts to convergence at equal final fitness.","acceptance_criteria":"Speedup factor measured across \u003e=10 mutated topologies; decision recorded (expect order-of-magnitude; if \u003c2x, revisit §4.6 Phase-2 scoping)","notes":"Experiment script committed (experiments/warm_vs_cold.py, 1cc86c8) and machinery validated oracle-free; one mutated child scored through the oracle OK. Waiting on homemaker-py-gp2 reference run to finish, then execute under URB_NO_OCCLUSION=1 (3 parents x 400 evals + 12 children x 2 x 200 evals, ~1.5-2 h oracle time). Default budgets: parent 400, child 200; target = evals to 95% of best final.","status":"closed","priority":1,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-06-11T23:36:58Z","created_by":"Bruno Postle","updated_at":"2026-06-12T11:44:45Z","closed_at":"2026-06-12T11:44:45Z","close_reason":"Measured (URB_NO_OCCLUSION=1, parent budget 400, child 200, 12 single mutations across 3 designs): cold start reached 95% of warm final in 0/12 cases within budget — speedup unbounded at practical budgets; warm finals beat cold finals x1.2-x4 in 12/12; 6/12 warm starts were within 95% at 1 eval (near-neutral mutations). Decision: Lamarckian warm-starting is MANDATORY in the memetic driver (homemaker-py-b39), not an optimisation; cold starts produce strictly worse geometry at equal budget. Note: 2 undivides were exactly fitness-neutral (same-type merge == Merge_Divided equivalence) — locality datum for homemaker-py-nyb.","dependencies":[{"issue_id":"homemaker-py-8cs","depends_on_id":"homemaker-py-1p0","type":"blocks","created_at":"2026-06-12T00:39:34Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"homemaker-py-av5","title":"Batched oracle: score many .dom files per invocation","description":"oracle.py currently scores one .dom per urb-fitness.pl call (~1.65 s/dom). DESIGN.md §4.6: batching amortises Perl startup to ~0.99 s/dom and is required so population/batch optimisers can score a whole generation in one oracle call. Extend oracle.py with a batch API: write N .dom files, one perl invocation, parse N .score/.fails pairs. Keep the single-file path for compatibility.","acceptance_criteria":"Batch of 35 corpus files scores in one perl invocation; per-file results identical to single-file calls; measured s/dom reported","status":"closed","priority":1,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:36:56Z","created_by":"Bruno Postle","updated_at":"2026-06-12T00:14:06Z","started_at":"2026-06-11T23:50:40Z","closed_at":"2026-06-12T00:14:06Z","close_reason":"score_batch() lands in oracle.py; 35-file corpus parity verified single-vs-batch (1e-12 rel fitness, exact fail sets); 0.98 s/dom batched vs 1.27 single, x1.30","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"homemaker-py-av5","title":"Batched oracle: score many .dom files per invocation","description":"oracle.py currently scores one .dom per urb-fitness.pl call (~1.65 s/dom). DESIGN.md §4.6: batching amortises Perl startup to ~0.99 s/dom and is required so population/batch optimisers can score a whole generation in one oracle call. Extend oracle.py with a batch API: write N .dom files, one perl invocation, parse N .score/.fails pairs. Keep the single-file path for compatibility.","acceptance_criteria":"Batch of 35 corpus files scores in one perl invocation; per-file results identical to single-file calls; measured s/dom reported","status":"closed","priority":1,"issue_type":"task","assignee":"Bruno Postle","owner":"bruno@postle.net","created_at":"2026-06-11T23:36:56Z","created_by":"Bruno Postle","updated_at":"2026-06-12T00:14:06Z","started_at":"2026-06-11T23:50:40Z","closed_at":"2026-06-12T00:14:06Z","close_reason":"score_batch() lands in oracle.py; 35-file corpus parity verified single-vs-batch (1e-12 rel fitness, exact fail sets); 0.98 s/dom batched vs 1.27 single, x1.30","dependency_count":0,"dependent_count":1,"comment_count":0}
{"_type":"issue","id":"homemaker-py-tco","title":"A/B harnesses should report the minimum detectable difference for the N they run","description":"Two independent findings this session say the project's A/B protocols are routinely underpowered for the margins they report:\\n\\n §38.19 programme-house needed N=60 to resolve an effect its own protocol claimed at N=20 (p ~= 0.069 at N=20, 0.017 at N=60)\\n §38.21 harbor's paired sd is 6.19 fails, so n=3 resolves nothing finer than ~15.4 fails -- yet every recorded harbor margin is below that, and 25% of 3-seed subsets show a clean 3/3 sweep by chance\\n\\nThe fix is procedural and cheap. The A/B harnesses (run_*_ab.sh, ab_*.py, rerun_1ph_protocol.sh) should print, alongside the result, the minimum difference their N and observed sd could have detected -- so an underpowered verdict is visible AT THE POINT IT IS MADE rather than years later.\\n\\nA one-line addition to each harness's summary: given the paired diffs it already computes, report and flag when the observed margin is below it. Optionally refuse to declare a winner in that case.\\n\\nThis is not about re-running old A/Bs (§38.21 covers harbor, §38.19 programme-house); it is about not generating more of them.","acceptance_criteria":"The shared A/B summary path reports the minimum detectable difference for the N actually run, and flags a verdict whose margin falls below it; applied to at least rerun_1ph_protocol.sh and ab_ssz_search.py.","status":"open","priority":2,"issue_type":"task","owner":"noreply@anthropic.com","created_at":"2026-08-29T19:34:30Z","created_by":"Claude","updated_at":"2026-08-29T19:34:30Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"homemaker-py-ioe","title":"Is collapse_insearch=True still the right default under the current objective?","description":"The default was flipped OFF -\u003e ON by homemaker-py-1ph (DESIGN.md §20, 2026-07-24) on the strength of a programme-house N=20 sweep: mean 7.95 -\u003e 7.10, 11W/6L/3T, paired t p ~= 0.028. homemaker-py-d86 (§38.18) has now confirmed that verdict was sound FOR ITS OWN ERA -- it reproduces on a pre-iio commit, and the iio stale-share bug is structurally unreachable on that protocol because programme-house declares count: 1 for every code, so no leaf ever carries a share.\n\nBut the objective has changed substantially since, three times over, and all of it after 1ph:\n\n §39.4 the generic-namespace fix -- codes like cr1 were being read as generic\n circulation, so 14% of harbor's programme was silently optional\n §38.10 / §38.11 crinkliness declared per space; 14 corpus spaces now declare\n crinkliness: none\n §38.12 the missing-space cascade no longer weighted by YAML verbosity, a fixed\n 5 fails per missing instance instead of 3-5\n\ncollapse_insearch runs collapse_global inside every fitness eval, and collapse_global's assignment is valued against exactly the quality factors those changes touched. So the ON-beats-OFF margin was measured against an objective that no longer exists. The direction is plausibly unchanged -- but it is currently an assumption carried on a superseded measurement, and it is a DEFAULT, so every run inherits it.\n\nThe protocol and harness already exist: experiments/rerun_1ph_protocol.sh runs programme-house, budget 3000, 4 workers, seeds 1-20, ON vs OFF, both arms finished with --collapse, and takes about 6 minutes.\n\nNote when re-running: n_workers is an algorithm parameter (§38.17), so keep 4 workers to stay comparable with the published protocol, and record it with the result.","acceptance_criteria":"The 1ph protocol re-run at N=20 on the current codebase and objective, with the ON-vs-OFF verdict either reconfirmed or restated; if the margin has moved materially, DESIGN.md §20's default-flip rationale is updated to say so and the default is reconsidered on the new numbers.","status":"closed","priority":2,"issue_type":"task","assignee":"Claude","owner":"noreply@anthropic.com","created_at":"2026-08-29T13:36:18Z","created_by":"Claude","updated_at":"2026-08-29T13:57:45Z","started_at":"2026-08-29T13:36:32Z","closed_at":"2026-08-29T13:57:45Z","close_reason":"Re-validated: the default STANDS, but with two caveats worth carrying\n(DESIGN.md §38.19).\n\nRe-ran the 1ph protocol as published on the current codebase and objective --\nprogramme-house, budget 3000, 4 workers, ON vs OFF, both arms finished with\n--collapse.\n\n N OFF ON W/L/T diff t p\n published 1ph (07-24) 20 7.95 7.10 11/6/3 +0.85 2.38 0.028\n historical re-run (§38.18) 20 8.05 7.10 11/6/3 +0.95 2.59 --\n current objective 20 7.85 7.15 10/7/3 +0.70 1.82 0.069\n current objective 40 7.60 7.03 21/14/5 +0.57 2.01 0.045\n current objective 60 7.58 7.02 29/19/12 +0.57 2.45 0.017\n\nAt N=60: mean diff +0.567 fails/seed, paired t=2.454 (df=59), p=0.0171 exact,\n95% CI [+0.105, +1.029] excluding zero. Wilcoxon signed-rank cross-check agrees\n(p=0.0138), which matters because fail counts are small integers and normality\nis not obvious.\n\nCaveat 1: the effect is about a third smaller than published (+0.57 vs +0.85).\nPartly regression from a slightly lucky N=20 draw, partly plausible real erosion\n-- several fails collapse_global used to clear have been redefined out of\nexistence or made harder by §39.4 / §38.10-12.\n\nCaveat 2, the more useful one: THE PUBLISHED N=20 CAN NO LONGER DETECT ITS OWN\nEFFECT. At exactly the published sample size the current answer is p ~= 0.069, a\nnull by the conventional threshold. Had I run N=20 and stopped, the honest report\nwould have been \"the 1ph verdict no longer reproduces\" and the default would have\nlooked unjustified. It took N=60 to resolve. That is the \"8sh/1ph/qi6/lj3\npattern\" this log already warns about, now biting the flagship result itself.\nAny future re-validation of this default needs N \u003e= 40; N=20 should not be\ntrusted to settle it either way.\n\n§20 annotated in place so a reader of the original claim sees the current figure.\nHarness now takes a seed range (APPEND=1 to extend a sweep); results in\nexperiments/results/ioe_1ph_current_objective.tsv.\n","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-ioe","title":"Is collapse_insearch=True still the right default under the current objective?","description":"The default was flipped OFF -\u003e ON by homemaker-py-1ph (DESIGN.md §20, 2026-07-24) on the strength of a programme-house N=20 sweep: mean 7.95 -\u003e 7.10, 11W/6L/3T, paired t p ~= 0.028. homemaker-py-d86 (§38.18) has now confirmed that verdict was sound FOR ITS OWN ERA -- it reproduces on a pre-iio commit, and the iio stale-share bug is structurally unreachable on that protocol because programme-house declares count: 1 for every code, so no leaf ever carries a share.\n\nBut the objective has changed substantially since, three times over, and all of it after 1ph:\n\n §39.4 the generic-namespace fix -- codes like cr1 were being read as generic\n circulation, so 14% of harbor's programme was silently optional\n §38.10 / §38.11 crinkliness declared per space; 14 corpus spaces now declare\n crinkliness: none\n §38.12 the missing-space cascade no longer weighted by YAML verbosity, a fixed\n 5 fails per missing instance instead of 3-5\n\ncollapse_insearch runs collapse_global inside every fitness eval, and collapse_global's assignment is valued against exactly the quality factors those changes touched. So the ON-beats-OFF margin was measured against an objective that no longer exists. The direction is plausibly unchanged -- but it is currently an assumption carried on a superseded measurement, and it is a DEFAULT, so every run inherits it.\n\nThe protocol and harness already exist: experiments/rerun_1ph_protocol.sh runs programme-house, budget 3000, 4 workers, seeds 1-20, ON vs OFF, both arms finished with --collapse, and takes about 6 minutes.\n\nNote when re-running: n_workers is an algorithm parameter (§38.17), so keep 4 workers to stay comparable with the published protocol, and record it with the result.","acceptance_criteria":"The 1ph protocol re-run at N=20 on the current codebase and objective, with the ON-vs-OFF verdict either reconfirmed or restated; if the margin has moved materially, DESIGN.md §20's default-flip rationale is updated to say so and the default is reconsidered on the new numbers.","status":"closed","priority":2,"issue_type":"task","assignee":"Claude","owner":"noreply@anthropic.com","created_at":"2026-08-29T13:36:18Z","created_by":"Claude","updated_at":"2026-08-29T13:57:45Z","started_at":"2026-08-29T13:36:32Z","closed_at":"2026-08-29T13:57:45Z","close_reason":"Re-validated: the default STANDS, but with two caveats worth carrying\n(DESIGN.md §38.19).\n\nRe-ran the 1ph protocol as published on the current codebase and objective --\nprogramme-house, budget 3000, 4 workers, ON vs OFF, both arms finished with\n--collapse.\n\n N OFF ON W/L/T diff t p\n published 1ph (07-24) 20 7.95 7.10 11/6/3 +0.85 2.38 0.028\n historical re-run (§38.18) 20 8.05 7.10 11/6/3 +0.95 2.59 --\n current objective 20 7.85 7.15 10/7/3 +0.70 1.82 0.069\n current objective 40 7.60 7.03 21/14/5 +0.57 2.01 0.045\n current objective 60 7.58 7.02 29/19/12 +0.57 2.45 0.017\n\nAt N=60: mean diff +0.567 fails/seed, paired t=2.454 (df=59), p=0.0171 exact,\n95% CI [+0.105, +1.029] excluding zero. Wilcoxon signed-rank cross-check agrees\n(p=0.0138), which matters because fail counts are small integers and normality\nis not obvious.\n\nCaveat 1: the effect is about a third smaller than published (+0.57 vs +0.85).\nPartly regression from a slightly lucky N=20 draw, partly plausible real erosion\n-- several fails collapse_global used to clear have been redefined out of\nexistence or made harder by §39.4 / §38.10-12.\n\nCaveat 2, the more useful one: THE PUBLISHED N=20 CAN NO LONGER DETECT ITS OWN\nEFFECT. At exactly the published sample size the current answer is p ~= 0.069, a\nnull by the conventional threshold. Had I run N=20 and stopped, the honest report\nwould have been \"the 1ph verdict no longer reproduces\" and the default would have\nlooked unjustified. It took N=60 to resolve. That is the \"8sh/1ph/qi6/lj3\npattern\" this log already warns about, now biting the flagship result itself.\nAny future re-validation of this default needs N \u003e= 40; N=20 should not be\ntrusted to settle it either way.\n\n§20 annotated in place so a reader of the original claim sees the current figure.\nHarness now takes a seed range (APPEND=1 to extend a sweep); results in\nexperiments/results/ioe_1ph_current_objective.tsv.\n","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"homemaker-py-vjd","title":"cpsat assignment ~7.5x slower after the 3qj adjacency: re-check §39.5's cpsat-vs-greedy verdict","description":"Declaring harbor's t -\u003e n adjacency (homemaker-py-3qj, DESIGN.md §38.14) made the CP-SAT room-labelling model markedly harder. constructive_topology seeding, 3-seed average:\\n\\n harbor greedy 0.06s -\u003e 0.06s (unchanged) cpsat 0.28s -\u003e 2.11s (7.5x)\\n maple greedy 0.03s -\u003e 0.03s (unchanged) cpsat 0.47s -\u003e 1.37s (2.9x)\\n\\nassign_solver defaults to greedy so ordinary runs pay nothing, and mutate_reassign/enable_reassign are opt-in too. But §39.5 concluded cpsat beats greedy on both programmes, and that was measured on a cheaper problem than the corpus now poses. The verdict needs re-checking on quality-per-second, not just quality.\\n\\nAlso worth checking whether cpsat.max_deterministic_time is now being hit, which would mean it is returning early rather than solving -- that would change the quality side of the comparison too, silently.","acceptance_criteria":"cpsat vs greedy re-measured on the current corpus for both solution quality AND wall time; §39.5's verdict either reconfirmed or restated; if max_deterministic_time is being hit, that is recorded and the limit reconsidered.","status":"closed","priority":2,"issue_type":"task","assignee":"Claude","owner":"noreply@anthropic.com","created_at":"2026-08-29T10:57:26Z","created_by":"Claude","updated_at":"2026-08-29T14:47:36Z","started_at":"2026-08-29T14:20:49Z","closed_at":"2026-08-29T14:47:36Z","close_reason":"Re-measured. Three findings (DESIGN.md §38.20).\n\n1. A LIVE BUG IN THE CAP, found on the way. solve_room_labels sets a\ndeterministic work-unit budget (max_deterministic_time=4.0) and a wall-clock\nbackstop, with the comment that the wall clock is \"a pathological-case backstop\nonly\". At its 2.0s value it had become THE BINDING CONSTRAINT: on harbor, 2 of\n24 solves returned FEASIBLE not OPTIMAL, wall time hit exactly 2010 ms, and the\ndeterministic budget was never reached (max 2.483 of 4.0). Those labellings were\nboth suboptimal AND load-dependent -- the wall clock is precisely the cap §39.5\nadded the deterministic one to escape. Cause: §38.14's `t -\u003e n` adjacency makes\nthe model much harder, and the 2s value dated from when solves took ~124 ms.\nRaised to 30s; now 24/24 harbor and 36/36 maple solves are OPTIMAL with the\ndeterministic budget still in headroom (max 3.569/4.0).\n\n2. THE VERDICT REVERSES. Re-measured deterministically (fdp's id()-ordering fix\nmeans the arms no longer differ by memory layout), 12 constructed seeds, scored\ncanonically:\n\n harbor greedy 722h/601s = 1323 0.079 s/seed\n harbor cpsat 908h/640s = 1548 1.623 s/seed\n maple greedy 777h/987s = 1764 0.063 s/seed\n maple cpsat 1213h/1043s= 2256 1.327 s/seed\n\ncpsat LOSES on both, +225 and +492 fails, at ~21x the seeding time, concentrated\nin hard fails.\n\n3. TIME AND QUALITY HAVE DIFFERENT CAUSES. Removing §38.14's `t -\u003e n` from\nharbor: cpsat goes 1.623 -\u003e 0.193 s/seed (8.4x faster) but still +205 vs greedy\n(was +225). So the adjacency explains the time blow-up and ~9% of the quality\ngap; the regression is otherwise pre-existing.\n\nSquaring with §39.5: that section records cpsat returning 194/180/171/182 over\nfour identical 10-seed aggregates before the determinism work. Its 10-fail\nharbor margin (102 vs 92) sits well inside a noise band that wide, and was\nmeasured with fdp's id()-ordered room_slots still live. So the seeder-level\n\"cpsat wins\" claim was never established rather than being overturned. §39.5\nannotated in place.\n\nCaveat stated in the write-up: absolute totals are ~6x §39.5's because the\nobjective has changed (§39.4, §38.10-12), so they are not directly comparable to\nthat table. The greedy-vs-cpsat comparison within this measurement is\nlike-for-like and is what the verdict rests on.\n\nNo default changes -- assign_solver was already greedy for §37.7's independent\nreason, and this reinforces it. What changes is that \"cpsat wins the seeder A/B\"\nshould no longer be cited as a reason to pursue it.\n\nCost recorded and filed as homemaker-py-2xk: the cap fix takes the test suite\nfrom ~4.5 to ~10 min, and the tests cannot opt out because constructive_topology\ndoes not thread the solver limits through.\n","comments":[{"id":"01a04dfd-ca76-7a21-b18d-d2af9ccd9ef4","issue_id":"homemaker-py-vjd","author":"Claude","text":"Correction: the close note above cites the follow-up as homemaker-py-2xk. That\nID does not exist -- I wrote it before creating the issue. The real one is\nhomemaker-py-7t1 (\"cpsat solver limits are not threadable from\nconstructive_topology, so tests pay full solve cost\"). DESIGN.md §38.20 has been\ncorrected to match.","created_at":"2026-08-29T14:47:53Z"}],"dependency_count":0,"dependent_count":0,"comment_count":1} {"_type":"issue","id":"homemaker-py-vjd","title":"cpsat assignment ~7.5x slower after the 3qj adjacency: re-check §39.5's cpsat-vs-greedy verdict","description":"Declaring harbor's t -\u003e n adjacency (homemaker-py-3qj, DESIGN.md §38.14) made the CP-SAT room-labelling model markedly harder. constructive_topology seeding, 3-seed average:\\n\\n harbor greedy 0.06s -\u003e 0.06s (unchanged) cpsat 0.28s -\u003e 2.11s (7.5x)\\n maple greedy 0.03s -\u003e 0.03s (unchanged) cpsat 0.47s -\u003e 1.37s (2.9x)\\n\\nassign_solver defaults to greedy so ordinary runs pay nothing, and mutate_reassign/enable_reassign are opt-in too. But §39.5 concluded cpsat beats greedy on both programmes, and that was measured on a cheaper problem than the corpus now poses. The verdict needs re-checking on quality-per-second, not just quality.\\n\\nAlso worth checking whether cpsat.max_deterministic_time is now being hit, which would mean it is returning early rather than solving -- that would change the quality side of the comparison too, silently.","acceptance_criteria":"cpsat vs greedy re-measured on the current corpus for both solution quality AND wall time; §39.5's verdict either reconfirmed or restated; if max_deterministic_time is being hit, that is recorded and the limit reconsidered.","status":"closed","priority":2,"issue_type":"task","assignee":"Claude","owner":"noreply@anthropic.com","created_at":"2026-08-29T10:57:26Z","created_by":"Claude","updated_at":"2026-08-29T14:47:36Z","started_at":"2026-08-29T14:20:49Z","closed_at":"2026-08-29T14:47:36Z","close_reason":"Re-measured. Three findings (DESIGN.md §38.20).\n\n1. A LIVE BUG IN THE CAP, found on the way. solve_room_labels sets a\ndeterministic work-unit budget (max_deterministic_time=4.0) and a wall-clock\nbackstop, with the comment that the wall clock is \"a pathological-case backstop\nonly\". At its 2.0s value it had become THE BINDING CONSTRAINT: on harbor, 2 of\n24 solves returned FEASIBLE not OPTIMAL, wall time hit exactly 2010 ms, and the\ndeterministic budget was never reached (max 2.483 of 4.0). Those labellings were\nboth suboptimal AND load-dependent -- the wall clock is precisely the cap §39.5\nadded the deterministic one to escape. Cause: §38.14's `t -\u003e n` adjacency makes\nthe model much harder, and the 2s value dated from when solves took ~124 ms.\nRaised to 30s; now 24/24 harbor and 36/36 maple solves are OPTIMAL with the\ndeterministic budget still in headroom (max 3.569/4.0).\n\n2. THE VERDICT REVERSES. Re-measured deterministically (fdp's id()-ordering fix\nmeans the arms no longer differ by memory layout), 12 constructed seeds, scored\ncanonically:\n\n harbor greedy 722h/601s = 1323 0.079 s/seed\n harbor cpsat 908h/640s = 1548 1.623 s/seed\n maple greedy 777h/987s = 1764 0.063 s/seed\n maple cpsat 1213h/1043s= 2256 1.327 s/seed\n\ncpsat LOSES on both, +225 and +492 fails, at ~21x the seeding time, concentrated\nin hard fails.\n\n3. TIME AND QUALITY HAVE DIFFERENT CAUSES. Removing §38.14's `t -\u003e n` from\nharbor: cpsat goes 1.623 -\u003e 0.193 s/seed (8.4x faster) but still +205 vs greedy\n(was +225). So the adjacency explains the time blow-up and ~9% of the quality\ngap; the regression is otherwise pre-existing.\n\nSquaring with §39.5: that section records cpsat returning 194/180/171/182 over\nfour identical 10-seed aggregates before the determinism work. Its 10-fail\nharbor margin (102 vs 92) sits well inside a noise band that wide, and was\nmeasured with fdp's id()-ordered room_slots still live. So the seeder-level\n\"cpsat wins\" claim was never established rather than being overturned. §39.5\nannotated in place.\n\nCaveat stated in the write-up: absolute totals are ~6x §39.5's because the\nobjective has changed (§39.4, §38.10-12), so they are not directly comparable to\nthat table. The greedy-vs-cpsat comparison within this measurement is\nlike-for-like and is what the verdict rests on.\n\nNo default changes -- assign_solver was already greedy for §37.7's independent\nreason, and this reinforces it. What changes is that \"cpsat wins the seeder A/B\"\nshould no longer be cited as a reason to pursue it.\n\nCost recorded and filed as homemaker-py-2xk: the cap fix takes the test suite\nfrom ~4.5 to ~10 min, and the tests cannot opt out because constructive_topology\ndoes not thread the solver limits through.\n","comments":[{"id":"01a04dfd-ca76-7a21-b18d-d2af9ccd9ef4","issue_id":"homemaker-py-vjd","author":"Claude","text":"Correction: the close note above cites the follow-up as homemaker-py-2xk. That\nID does not exist -- I wrote it before creating the issue. The real one is\nhomemaker-py-7t1 (\"cpsat solver limits are not threadable from\nconstructive_topology, so tests pay full solve cost\"). DESIGN.md §38.20 has been\ncorrected to match.","created_at":"2026-08-29T14:47:53Z"}],"dependency_count":0,"dependent_count":0,"comment_count":1}
{"_type":"issue","id":"homemaker-py-9gj","title":"quality_uncrinkliness returns a flat hard 0.0, so the objective cannot rank two equally-buried layouts","description":"Narrowed remnant of homemaker-py-ssz after the owner's daylight ruling (DESIGN.md §38.11). A buried leaf usually IS a defect -- corridors and WCs included -- so scoring it badly is correct. The residual complaint is not that the value is low, it is that it is FLAT: quality_uncrinkliness returns exactly 0.0 for every zero-exposure leaf, and since evaluate_leaf multiplies factors into quality and process_storey accumulates value += quality * rate * area, two layouts that differ only in how badly buried their rooms are score identically.\n\nSo the objective gives the search no gradient to descend in precisely the region it most needs to escape. This is a search-mechanics problem, not a calibration one, and it should be judged on whether it helps the search escape -- NOT on fail counts, which by construction it will not move (the fails are real and should stay).\n\nNote the trap recorded in §38.9: an arm optimised under a modified objective must not be scored under the objective it modifies, and equally must not be scored under its own. For a pure gradient change that emits the same fail set, stock scoring IS valid -- that is the one case where the yardstick is sound.","acceptance_criteria":"A variant that keeps the fail set byte-identical to stock (every currently-failing leaf still fails) but is monotone in how buried a leaf is; A/B at fixed budget on harbor + maple with enough seeds to see past the one-seed variance that made the §38.8 n=3 result undecidable.","status":"open","priority":2,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-28T23:14:04Z","created_by":"Claude","updated_at":"2026-08-28T23:14:04Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-9gj","title":"quality_uncrinkliness returns a flat hard 0.0, so the objective cannot rank two equally-buried layouts","description":"Narrowed remnant of homemaker-py-ssz after the owner's daylight ruling (DESIGN.md §38.11). A buried leaf usually IS a defect -- corridors and WCs included -- so scoring it badly is correct. The residual complaint is not that the value is low, it is that it is FLAT: quality_uncrinkliness returns exactly 0.0 for every zero-exposure leaf, and since evaluate_leaf multiplies factors into quality and process_storey accumulates value += quality * rate * area, two layouts that differ only in how badly buried their rooms are score identically.\n\nSo the objective gives the search no gradient to descend in precisely the region it most needs to escape. This is a search-mechanics problem, not a calibration one, and it should be judged on whether it helps the search escape -- NOT on fail counts, which by construction it will not move (the fails are real and should stay).\n\nNote the trap recorded in §38.9: an arm optimised under a modified objective must not be scored under the objective it modifies, and equally must not be scored under its own. For a pure gradient change that emits the same fail set, stock scoring IS valid -- that is the one case where the yardstick is sound.","acceptance_criteria":"A variant that keeps the fail set byte-identical to stock (every currently-failing leaf still fails) but is monotone in how buried a leaf is; A/B at fixed budget on harbor + maple with enough seeds to see past the one-seed variance that made the §38.8 n=3 result undecidable.","status":"open","priority":2,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-28T23:14:04Z","created_by":"Claude","updated_at":"2026-08-28T23:14:04Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"homemaker-py-7b7","title":"health-centre demands 131% of its plot: the programme is unsatisfiable as written","description":"`evolve._preflight` (homemaker-py-tdp, DESIGN.md 39.11) reports health-centre demanding 240 m2 of floor per storey on a 183 m2 plot -- 131%. It is 1 storey (n_storeys_required=1, storey_minimum=1), so there is nowhere for the overflow to go.\n\nThe consequence is visible in every evaluated layout: 100% of rooms come out undersized, uniformly, at a median 0.60x their declared target. No search can fix this -- quality_size is being asked for something the plot cannot supply, so the size gaussian is pinned near-zero across the whole design and contributes no useful gradient. Contrast harbor-house and maple-court, where the seeder hits targets at median 1.01x.\n\nThis is a corpus data problem, not an engine problem. Either the plot is too small or the programme's sizes/counts were estimated too generously (the CLAUDE.md note that all corpus targets were 'estimated many years ago and never changed' applies).\n\nOptions, roughly in order of honesty:\n 1. enlarge the plot in examples/health-centre/init.dom to ~1.4x\n 2. scale down size/count in patterns.config until demand fits with headroom\n 3. raise the storey count so the demand spreads over 2 levels\n 4. leave it and treat health-centre as a deliberate over-tight brief, documented as such\n\nWhichever is chosen, note it in DESIGN.md 39.11 so the pre-flight warning is not read as a bug in the check.","acceptance_criteria":"health-centre's demanded area per storey fits its plot with headroom, OR the programme is explicitly documented as a deliberately over-tight brief; `evolve._preflight` no longer reports it as an unexplained anomaly; median room area / (target * share) on a constructed seed is materially above 0.60x.","status":"closed","priority":2,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-26T16:20:31Z","created_by":"Claude","updated_at":"2026-08-29T10:20:00Z","closed_at":"2026-08-29T10:20:00Z","close_reason":"Fixed per the owner's ruling: enlarge the plot, sized assuming a courtyard\n(DESIGN.md §38.13).\n\nThe plot is a quadrilateral in this engine, so the courtyard is interior space\nthe search carves out, not a hole in the site. Sizing therefore has to allow for\nthree things, only one of which the programme declares: rooms 240 m2, circulation\n~65 m2 (~27%, NOT in demand -- the search creates C leaves), courtyard ~36 m2.\n\nScaled about the polygon centroid by k = 1.4606, chosen so the INSET area (what\nleaves actually get, after wall_outer) lands on 400 m2. Centroid scaling keeps\nthe site's irregular shape and its one private edge -- same site, larger.\n\n plot 183.2 -\u003e 400.0 m2\n rooms / plot 131% -\u003e 60% (harbor's ratio exactly, and harbor works)\n daylit perim 41.5 -\u003e 61.3 m (49.4 needed)\n median room area / (target x share) 0.60x -\u003e 1.00x\n\nThat last figure is the one that matters: 0.60x with 100% of rooms undersized\nwas the geometric signature of the infeasibility, and it is now level with\nharbor/maple at 1.01x.\n\nThe courtyard remains REQUIRED by the geometry rather than merely permitted: a\nroom is at most 1.6202*h = 4.86 m deep before failing crinkliness, so a ~20x20 m\nplot with a daylit ring leaves a 10.3 x 10.3 m, 106 m2 core that cannot reach an\nexternal wall. Enlarging did not remove the pressure that produces a courtyard,\nit made room for one.\n\nevolve._preflight is now silent on health-centre. Unblocks homemaker-py-7xb.\n","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"homemaker-py-7b7","title":"health-centre demands 131% of its plot: the programme is unsatisfiable as written","description":"`evolve._preflight` (homemaker-py-tdp, DESIGN.md 39.11) reports health-centre demanding 240 m2 of floor per storey on a 183 m2 plot -- 131%. It is 1 storey (n_storeys_required=1, storey_minimum=1), so there is nowhere for the overflow to go.\n\nThe consequence is visible in every evaluated layout: 100% of rooms come out undersized, uniformly, at a median 0.60x their declared target. No search can fix this -- quality_size is being asked for something the plot cannot supply, so the size gaussian is pinned near-zero across the whole design and contributes no useful gradient. Contrast harbor-house and maple-court, where the seeder hits targets at median 1.01x.\n\nThis is a corpus data problem, not an engine problem. Either the plot is too small or the programme's sizes/counts were estimated too generously (the CLAUDE.md note that all corpus targets were 'estimated many years ago and never changed' applies).\n\nOptions, roughly in order of honesty:\n 1. enlarge the plot in examples/health-centre/init.dom to ~1.4x\n 2. scale down size/count in patterns.config until demand fits with headroom\n 3. raise the storey count so the demand spreads over 2 levels\n 4. leave it and treat health-centre as a deliberate over-tight brief, documented as such\n\nWhichever is chosen, note it in DESIGN.md 39.11 so the pre-flight warning is not read as a bug in the check.","acceptance_criteria":"health-centre's demanded area per storey fits its plot with headroom, OR the programme is explicitly documented as a deliberately over-tight brief; `evolve._preflight` no longer reports it as an unexplained anomaly; median room area / (target * share) on a constructed seed is materially above 0.60x.","status":"closed","priority":2,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-26T16:20:31Z","created_by":"Claude","updated_at":"2026-08-29T10:20:00Z","closed_at":"2026-08-29T10:20:00Z","close_reason":"Fixed per the owner's ruling: enlarge the plot, sized assuming a courtyard\n(DESIGN.md §38.13).\n\nThe plot is a quadrilateral in this engine, so the courtyard is interior space\nthe search carves out, not a hole in the site. Sizing therefore has to allow for\nthree things, only one of which the programme declares: rooms 240 m2, circulation\n~65 m2 (~27%, NOT in demand -- the search creates C leaves), courtyard ~36 m2.\n\nScaled about the polygon centroid by k = 1.4606, chosen so the INSET area (what\nleaves actually get, after wall_outer) lands on 400 m2. Centroid scaling keeps\nthe site's irregular shape and its one private edge -- same site, larger.\n\n plot 183.2 -\u003e 400.0 m2\n rooms / plot 131% -\u003e 60% (harbor's ratio exactly, and harbor works)\n daylit perim 41.5 -\u003e 61.3 m (49.4 needed)\n median room area / (target x share) 0.60x -\u003e 1.00x\n\nThat last figure is the one that matters: 0.60x with 100% of rooms undersized\nwas the geometric signature of the infeasibility, and it is now level with\nharbor/maple at 1.01x.\n\nThe courtyard remains REQUIRED by the geometry rather than merely permitted: a\nroom is at most 1.6202*h = 4.86 m deep before failing crinkliness, so a ~20x20 m\nplot with a daylit ring leaves a 10.3 x 10.3 m, 106 m2 core that cannot reach an\nexternal wall. Enlarging did not remove the pressure that produces a courtyard,\nit made room for one.\n\nevolve._preflight is now silent on health-centre. Unblocks homemaker-py-7xb.\n","dependency_count":0,"dependent_count":1,"comment_count":0}
{"_type":"issue","id":"homemaker-py-3qj","title":"Programmes do not declare bedroom/treatment-room to toilet adjacency, so the Brand adaptability credit is never earned","description":"Established while settling homemaker-py-sel. A toilet adjacent to a sleeping or treatment room is a positive even with no door between them -- Stewart Brand, How Buildings Learn: the building may need it knocked through later, and the adjacency is what makes that possible.\\n\\nThe engine already supports this. fitness._evaluate_full runs graph.check_adjacency against graph_base_pre, the UNFILTERED adjacency graph, so a declared adjacency requirement is satisfied by a neighbouring room regardless of the edges graph.has_circulation later strips for routing. (The stripping is correct on its own terms -- you cannot walk through a bedroom to reach the loo.)\\n\\nBut it is only ever scored where a programme DECLARES it, and only one corpus programme does:\\n programme-house (+ derivatives) t1 -\u003e adjacency: [b1] DECLARED\\n harbor-house t (Bathroom, count 6) vs r / n (sleeping) not declared\\n maple-court t, tt vs r / n not declared\\n health-centre t9 / t10 vs tr1 (Treatment Room) not declared\\n\\nSo three of the four real programmes leave the adaptability credit on the table: the search has no reason to place a WC next to a dormitory or a treatment room, because nothing scores it.\\n\\nThis is programme authoring, not an engine change, and it is independent of the usage-key work -- it can land before or after.","acceptance_criteria":"harbor-house, maple-court and health-centre declare the sleeping/treatment-to-toilet adjacencies their briefs imply; re-baselined so the change in fail counts is attributed rather than absorbed.","status":"closed","priority":2,"issue_type":"task","owner":"noreply@anthropic.com","created_at":"2026-08-26T12:33:39Z","created_by":"Claude","updated_at":"2026-08-29T10:57:25Z","closed_at":"2026-08-29T10:57:25Z","close_reason":"Declared where the brief supports it (DESIGN.md §38.14).\n\n harbor-house t -\u003e n Bathrooms serve the Neighborhoods (communal sleeping).\n Both unpinned, 6 t / 5 n.\n maple-court tt -\u003e r Upper Bathrooms among Individual Rooms, both level 2,\n already 62% adjacent at seed time.\n\nNOT declared, and checking before declaring is what caught these:\n\n maple t -\u003e n is IMPOSSIBLE. Adjacency is evaluated per level (graph_base[li]),\n and maple pins t to level 0, n to level 1. Declaring it would have added six\n permanently unsatisfiable fails. The 0% seed-time rate I measured was a hard\n impossibility, not search difficulty. maple's ground floor has six bathrooms\n and exactly one sleeping room (Clinic Room x1) -- a ground-floor WC in a\n communal building is public, so Brand does not apply to it anyway.\n\n health-centre has no dedicated WC. The owner's ruling on treatment rooms was\n that one \"may give access to a toilet, but this would be a DEDICATED toilet\".\n t9 is a Public WC (x2), t10 a Staff WC; making either dedicated-adjacent to\n tr1 contradicts that. Earning the credit here needs a dedicated WC added to\n the brief -- programme authoring beyond this issue. Filed separately.\n\nBoth declarations are reachable (best of 8 seeds: 2/3 harbor, 2/2 maple), so the\nsearch gets a gradient not a permanent penalty. evolved-3M-nols-3: 84 -\u003e 89\nfails, all five the new requirement.\n\nCost: cpsat assignment got ~7.5x slower on harbor (0.28 -\u003e 2.11s per seed);\ngreedy, the default, is unchanged at 0.06s. Filed as a follow-up since it bears\non §39.5's cpsat-vs-greedy verdict.\n\nTwo tests were over-fitted to the old seeds and were repaired to assert their\nintent rather than relaxed: reassign now sweeps six constructive seeds (seed 0's\nbetter-seeded design legitimately has nothing to improve; 5 of 6 others fire),\nand repair_circulation asserts that repair strictly helps plus a \u003e=85% bar\ninstead of a sampled 100% (measured 25% -\u003e 92%, stable over 6 and 12 seeds).\n","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-3qj","title":"Programmes do not declare bedroom/treatment-room to toilet adjacency, so the Brand adaptability credit is never earned","description":"Established while settling homemaker-py-sel. A toilet adjacent to a sleeping or treatment room is a positive even with no door between them -- Stewart Brand, How Buildings Learn: the building may need it knocked through later, and the adjacency is what makes that possible.\\n\\nThe engine already supports this. fitness._evaluate_full runs graph.check_adjacency against graph_base_pre, the UNFILTERED adjacency graph, so a declared adjacency requirement is satisfied by a neighbouring room regardless of the edges graph.has_circulation later strips for routing. (The stripping is correct on its own terms -- you cannot walk through a bedroom to reach the loo.)\\n\\nBut it is only ever scored where a programme DECLARES it, and only one corpus programme does:\\n programme-house (+ derivatives) t1 -\u003e adjacency: [b1] DECLARED\\n harbor-house t (Bathroom, count 6) vs r / n (sleeping) not declared\\n maple-court t, tt vs r / n not declared\\n health-centre t9 / t10 vs tr1 (Treatment Room) not declared\\n\\nSo three of the four real programmes leave the adaptability credit on the table: the search has no reason to place a WC next to a dormitory or a treatment room, because nothing scores it.\\n\\nThis is programme authoring, not an engine change, and it is independent of the usage-key work -- it can land before or after.","acceptance_criteria":"harbor-house, maple-court and health-centre declare the sleeping/treatment-to-toilet adjacencies their briefs imply; re-baselined so the change in fail counts is attributed rather than absorbed.","status":"closed","priority":2,"issue_type":"task","owner":"noreply@anthropic.com","created_at":"2026-08-26T12:33:39Z","created_by":"Claude","updated_at":"2026-08-29T10:57:25Z","closed_at":"2026-08-29T10:57:25Z","close_reason":"Declared where the brief supports it (DESIGN.md §38.14).\n\n harbor-house t -\u003e n Bathrooms serve the Neighborhoods (communal sleeping).\n Both unpinned, 6 t / 5 n.\n maple-court tt -\u003e r Upper Bathrooms among Individual Rooms, both level 2,\n already 62% adjacent at seed time.\n\nNOT declared, and checking before declaring is what caught these:\n\n maple t -\u003e n is IMPOSSIBLE. Adjacency is evaluated per level (graph_base[li]),\n and maple pins t to level 0, n to level 1. Declaring it would have added six\n permanently unsatisfiable fails. The 0% seed-time rate I measured was a hard\n impossibility, not search difficulty. maple's ground floor has six bathrooms\n and exactly one sleeping room (Clinic Room x1) -- a ground-floor WC in a\n communal building is public, so Brand does not apply to it anyway.\n\n health-centre has no dedicated WC. The owner's ruling on treatment rooms was\n that one \"may give access to a toilet, but this would be a DEDICATED toilet\".\n t9 is a Public WC (x2), t10 a Staff WC; making either dedicated-adjacent to\n tr1 contradicts that. Earning the credit here needs a dedicated WC added to\n the brief -- programme authoring beyond this issue. Filed separately.\n\nBoth declarations are reachable (best of 8 seeds: 2/3 harbor, 2/2 maple), so the\nsearch gets a gradient not a permanent penalty. evolved-3M-nols-3: 84 -\u003e 89\nfails, all five the new requirement.\n\nCost: cpsat assignment got ~7.5x slower on harbor (0.28 -\u003e 2.11s per seed);\ngreedy, the default, is unchanged at 0.06s. Filed as a follow-up since it bears\non §39.5's cpsat-vs-greedy verdict.\n\nTwo tests were over-fitted to the old seeds and were repaired to assert their\nintent rather than relaxed: reassign now sweeps six constructive seeds (seed 0's\nbetter-seeded design legitimately has nothing to improve; 5 of 6 others fire),\nand repair_circulation asserts that repair strictly helps plus a \u003e=85% bar\ninstead of a sampled 100% (measured 25% -\u003e 92%, stable over 6 and 12 seeds).\n","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"homemaker-py-fdp","title":"constructive_topology is not bit-reproducible on the assign_solver=cpsat path","description":"Established while fixing §39.5. Narrowed but not closed:\\n\\n- cpsat.solve_room_labels IS now reproducible on every captured instance, after two fixes: sorting the model-build order (neighbors[slot] is a set of dom.Node, which hashes by id() -- a memory address -- so raw iteration made the model order vary and CP-SAT returned a different equally-optimal assignment each run), and adding max_deterministic_time alongside the wall-clock cap.\\n- operators.constructive_topology(assign_solver='greedy') IS reproducible.\\n- operators.constructive_topology(assign_solver='cpsat') is NOT: identical seed in the same process gives different leaf-type signatures across runs.\\n\\nSo something upstream of the solver in _assign_adjacency_aware still varies on the cpsat branch. Disabling _cpsat_relabel_settled does not fix it, so it is the first call site. Suspect another id()-hashed set of Nodes feeding slot/neighbour ordering.\\n\\nPlausible contributor to homemaker-py-b8g (parallel/BLAS non-determinism in n_workers\u003e1 runs) -- same id-keying hazard class as the documented geometry._cache issue. Meanwhile tests/test_operators.py::test_assign_cpsat_matches_or_beats_greedy_secondary_adjacency averages three repeats instead of asserting on one run.","acceptance_criteria":"constructive_topology(assign_solver='cpsat') produces identical output for identical seeds in-process and across processes; the A/B test can go back to a single-run assertion.","status":"closed","priority":2,"issue_type":"bug","assignee":"Claude","owner":"noreply@anthropic.com","created_at":"2026-08-26T10:06:55Z","created_by":"Claude","updated_at":"2026-08-29T11:45:19Z","started_at":"2026-08-29T11:35:49Z","closed_at":"2026-08-29T11:45:19Z","close_reason":"Fixed. One line (DESIGN.md §38.15):\n\n assignable = scope if scope is not None else set(leaves)\n noncirc = [L for L in assignable if L not in circ] # \u003c-- id() order\n\nassignable is a set of dom.Node, which hashes by id() -- a memory address -- so\niterating it ordered noncirc, and hence room_slots, by where the objects landed\nin memory. That varies between calls within one process, no seed involved.\n\nOnly cpsat showed it because the greedy path re-sorts every slot list with\n-idx[L] as a unique tiebreak and is immune to the incoming order; CP-SAT\nconsumes room_slots order as its model's variable order, and the labelling\nproblem has many equally-optimal solutions. Greedy was not more correct, it was\nmasking a defect that had been there all along.\n\nFix: noncirc = [L for L in leaves if L in assignable and L not in circ] --\niterate the tree-ordered list, use the set only for membership.\n\nVerified on programme-house, harbor-house and maple-court: 1 distinct signature\nover 5 runs on BOTH solvers, and 1 distinct signature across 4 processes with\ndifferent PYTHONHASHSEED (so context_types' string sets are not a second\nsource). That is stronger than the acceptance criteria asked for.\n\nMethod worth reusing: rather than guessing which set was at fault, I\ninstrumented solve_room_labels with an id-free fingerprint of inputs and\noutputs and isolated the FIRST call (later calls legitimately depend on earlier\nones via leaf types). Five runs, five distinct first-call inputs -\u003e fault is\nupstream of the solver, located in one step.\n\ntest_constructive_topology_is_bit_reproducible guards both solvers.\n\nBearing on other issues: every A/B on the cpsat path was comparing arms that\ndiffered partly by memory layout, §39.5's cpsat-vs-greedy verdict included\n(already down for re-measurement under homemaker-py-vjd). Same id()-keying\nhazard class as the geometry._cache issue and a plausible contributor to\nhomemaker-py-b8g, which stays open -- n_workers\u003e1 has its own BLAS mechanism and\nis not addressed here.\n","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-fdp","title":"constructive_topology is not bit-reproducible on the assign_solver=cpsat path","description":"Established while fixing §39.5. Narrowed but not closed:\\n\\n- cpsat.solve_room_labels IS now reproducible on every captured instance, after two fixes: sorting the model-build order (neighbors[slot] is a set of dom.Node, which hashes by id() -- a memory address -- so raw iteration made the model order vary and CP-SAT returned a different equally-optimal assignment each run), and adding max_deterministic_time alongside the wall-clock cap.\\n- operators.constructive_topology(assign_solver='greedy') IS reproducible.\\n- operators.constructive_topology(assign_solver='cpsat') is NOT: identical seed in the same process gives different leaf-type signatures across runs.\\n\\nSo something upstream of the solver in _assign_adjacency_aware still varies on the cpsat branch. Disabling _cpsat_relabel_settled does not fix it, so it is the first call site. Suspect another id()-hashed set of Nodes feeding slot/neighbour ordering.\\n\\nPlausible contributor to homemaker-py-b8g (parallel/BLAS non-determinism in n_workers\u003e1 runs) -- same id-keying hazard class as the documented geometry._cache issue. Meanwhile tests/test_operators.py::test_assign_cpsat_matches_or_beats_greedy_secondary_adjacency averages three repeats instead of asserting on one run.","acceptance_criteria":"constructive_topology(assign_solver='cpsat') produces identical output for identical seeds in-process and across processes; the A/B test can go back to a single-run assertion.","status":"closed","priority":2,"issue_type":"bug","assignee":"Claude","owner":"noreply@anthropic.com","created_at":"2026-08-26T10:06:55Z","created_by":"Claude","updated_at":"2026-08-29T11:45:19Z","started_at":"2026-08-29T11:35:49Z","closed_at":"2026-08-29T11:45:19Z","close_reason":"Fixed. One line (DESIGN.md §38.15):\n\n assignable = scope if scope is not None else set(leaves)\n noncirc = [L for L in assignable if L not in circ] # \u003c-- id() order\n\nassignable is a set of dom.Node, which hashes by id() -- a memory address -- so\niterating it ordered noncirc, and hence room_slots, by where the objects landed\nin memory. That varies between calls within one process, no seed involved.\n\nOnly cpsat showed it because the greedy path re-sorts every slot list with\n-idx[L] as a unique tiebreak and is immune to the incoming order; CP-SAT\nconsumes room_slots order as its model's variable order, and the labelling\nproblem has many equally-optimal solutions. Greedy was not more correct, it was\nmasking a defect that had been there all along.\n\nFix: noncirc = [L for L in leaves if L in assignable and L not in circ] --\niterate the tree-ordered list, use the set only for membership.\n\nVerified on programme-house, harbor-house and maple-court: 1 distinct signature\nover 5 runs on BOTH solvers, and 1 distinct signature across 4 processes with\ndifferent PYTHONHASHSEED (so context_types' string sets are not a second\nsource). That is stronger than the acceptance criteria asked for.\n\nMethod worth reusing: rather than guessing which set was at fault, I\ninstrumented solve_room_labels with an id-free fingerprint of inputs and\noutputs and isolated the FIRST call (later calls legitimately depend on earlier\nones via leaf types). Five runs, five distinct first-call inputs -\u003e fault is\nupstream of the solver, located in one step.\n\ntest_constructive_topology_is_bit_reproducible guards both solvers.\n\nBearing on other issues: every A/B on the cpsat path was comparing arms that\ndiffered partly by memory layout, §39.5's cpsat-vs-greedy verdict included\n(already down for re-measurement under homemaker-py-vjd). Same id()-keying\nhazard class as the geometry._cache issue and a plausible contributor to\nhomemaker-py-b8g, which stays open -- n_workers\u003e1 has its own BLAS mechanism and\nis not addressed here.\n","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"homemaker-py-0wr","title":"Re-check any harbor-house A/B decided by a small margin before the §39.4 namespace fix","description":"Until §39.4, harbor-house scored against a 32-instance EFFECTIVE programme -- cr1/of/st1/st2 (14% of room instances) were dropped by the count check and mis-parameterised by the generic c/o/s prefix rule. Any harbor A/B decided by a narrow margin was therefore decided against a programme missing a seventh of its rooms.\\n\\nOne confirmed casualty already: 2g7.5's CP-SAT seeder win (§37.7). Measured over 6 seeds on the corrected programme, greedy 102 / cpsat 114 -- cpsat now LOSES; on the old 32-instance programme it was 98/99, a tie, so the recorded win was marginal from the start. Control: on namespace-clean maple-court cpsat still wins 144/156, so the solver did not regress. Test marked xfail with a companion maple-court assertion; both assign_solver flags stay default off.\\n\\nWorth re-checking with the same lens: §13.9/§13.11 floors, §17/§20 collapse A/Bs, §23 ruin-recreate, §29/§30 beam width, §37.1 tiering -- anything whose harbor arm was close.","acceptance_criteria":"Each narrow-margin harbor result either re-measured on the corrected programme or annotated in DESIGN.md as pre-§39.4.","status":"open","priority":2,"issue_type":"task","owner":"noreply@anthropic.com","created_at":"2026-08-26T09:44:55Z","created_by":"Claude","updated_at":"2026-08-26T09:44:55Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-0wr","title":"Re-check any harbor-house A/B decided by a small margin before the §39.4 namespace fix","description":"Until §39.4, harbor-house scored against a 32-instance EFFECTIVE programme -- cr1/of/st1/st2 (14% of room instances) were dropped by the count check and mis-parameterised by the generic c/o/s prefix rule. Any harbor A/B decided by a narrow margin was therefore decided against a programme missing a seventh of its rooms.\\n\\nOne confirmed casualty already: 2g7.5's CP-SAT seeder win (§37.7). Measured over 6 seeds on the corrected programme, greedy 102 / cpsat 114 -- cpsat now LOSES; on the old 32-instance programme it was 98/99, a tie, so the recorded win was marginal from the start. Control: on namespace-clean maple-court cpsat still wins 144/156, so the solver did not regress. Test marked xfail with a companion maple-court assertion; both assign_solver flags stay default off.\\n\\nWorth re-checking with the same lens: §13.9/§13.11 floors, §17/§20 collapse A/Bs, §23 ruin-recreate, §29/§30 beam width, §37.1 tiering -- anything whose harbor arm was close.","acceptance_criteria":"Each narrow-margin harbor result either re-measured on the corrected programme or annotated in DESIGN.md as pre-§39.4.","status":"closed","priority":2,"issue_type":"task","assignee":"Claude","owner":"noreply@anthropic.com","created_at":"2026-08-26T09:44:55Z","created_by":"Claude","updated_at":"2026-08-29T19:34:29Z","started_at":"2026-08-29T18:59:31Z","closed_at":"2026-08-29T19:34:29Z","close_reason":"Answered, and the answer is broader than the question (DESIGN.md §38.21).\n\nThe issue asked which harbor A/Bs were decided by a NARROW margin before §39.4.\nMeasuring harbor's actual variance makes the margin-by-margin triage moot:\n\n harbor paired seed-to-seed sd = 6.19 fails (24 paired ON/OFF runs, budget 2500)\n -\u003e minimum difference detectable at n=3 (p\u003c0.05): 15.4 fails\n -\u003e minimum difference detectable at n=24: 3.9 fails\n\nEvery recorded harbor margin is below 15.4:\n §13.9 share_edge_cap 34.7 -\u003e 31.0 = 3.7\n §20 qpk collapse 80.3 -\u003e 72.0 = 8.3\n §23 f1d mixed, 1W/1L/1T\n §37.1 tiering hard 11.67 -\u003e 5.33 = 6.3\n §17 94g byte-identical, no margin claimed\n\nSo it is not that SOME harbor results were narrow -- NO harbor A/B run at three\nseeds could resolve the margin it reported, independently of what §39.4 did to\nthe programme. Of the 220 possible 3-seed subsets of the 24 runs, 56 (25%) show\na clean 3/3 sweep for ON: a 3/3 harbor result is close to a coin-flip artefact.\n\nRe-measured §20's harbor arm (the one backing a live default), same protocol:\n N=3 OFF 92.00 ON 89.33 2W/1L/0T +2.67 p=0.560\n N=12 OFF 92.75 ON 89.25 8W/3L/1T +3.50 p=0.076\n N=24 OFF 88.92 ON 87.71 13W/10L/1T +1.21 p=0.502 CI [-2.46,+4.88]\n\nNULL. The published \"harbor: ON wins 3/3, 80.3 -\u003e 72.0\" was a lucky draw -- even\nseeds 1-3 measured here give 2W/1L, not a sweep.\n\nConsequence: §20's claim that the qpk verdict \"holds at both example scales\ntested\" is WITHDRAWN and annotated in place. The collapse_insearch default rests\non programme-house alone (§38.19, N=60, +0.57, p=0.017). It is not refuted on\nharbor -- direction positive, indistinguishable from zero -- but harbor must not\nbe cited as corroboration.\n\nAcceptance criteria met: §20 re-measured; the rest annotated via §38.21's table,\nwhich states for each why its margin was unresolvable at n=3.\n\nNOTE this issue's own description is stale: it cites \"greedy 102 / cpsat 114 --\ncpsat now LOSES\" as a confirmed casualty, but §39.5 retracted that (it was the\n_matches bug, not §39.4). §38.20 independently finds cpsat loses, deterministically\nand for different reasons.\n\nStanding lesson, with §38.19: harbor at n=3 resolves nothing finer than ~15\nfails; programme-house at N=20 resolves nothing finer than ~1. Future A/Bs should\nstate their detectable difference before running.\n","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"homemaker-py-1i8","title":"Missing-space fail cascade weights rooms by patterns.config verbosity, not by design intent","description":"graph.check_space_counts emits, per missing room instance: 2 base fails ('missing required space: X' + '(critical)') plus one 'would need \u003ccheck\u003e' placeholder for each of size/width/proportion the programme HAPPENS to declare (has_size/has_width/has_proportion are literally 'size' in c etc. from the YAML). So a missing room costs 3 to 5 fails depending only on how many optional keys the author typed. Under value *= 0.5**len(failures) that is a 4x difference in fitness weight between two single rooms. Concretely in programme-house: missing b1 (declares size+width+proportion) = 5 fails = 1/32 penalty; missing t2 (declares size only) = 3 fails = 1/8 penalty. Same for harbor-house: n and cr1 cost 5 each, r and t cost 4 each. The tiered comparator inherits this -- n_hard is dominated by these cascades, so the primary search key is weighted by YAML verbosity.","design":"Either emit exactly one fail per missing instance (and let the cascade placeholders be informational, not counted), or normalise the cascade to a fixed count per instance independent of declared keys. Note this changes every historical fail-count baseline in DESIGN.md, so it needs its own A/B and a recorded re-baseline.","status":"closed","priority":2,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-25T23:15:00Z","created_by":"Claude","updated_at":"2026-08-29T09:33:24Z","closed_at":"2026-08-29T09:33:24Z","close_reason":"Fixed by emitting all three quality placeholders unconditionally (DESIGN.md\n§38.12). A fixed 5 fails per missing instance, independent of how the programme\nwas spelled.\n\nThe decisive evidence is that the two paths disagreed about the same room. A\nPRESENT room is checked on all three qualities regardless of declaration --\nget_space_params fills width and proportion from defaults, deriving width from\nsize when absent, so programme-house's t2 declares `size:` alone and still gets\na real width target of 1.633 it can fail on. Missing, it emitted one placeholder\nwhere b1 emitted three. The cascade stands in for the checks that could not run,\nand it was standing in for the wrong number of them.\n\nCorpus: 36 of 67 codes were under-counted, 31 already at 5. Max weight ratio\nbetween two single rooms goes 4x -\u003e 1x (programme-house), 2x -\u003e 1x (harbor,\nmaple), 1x -\u003e 1x (health-centre, already uniform).\n\nThis makes fail counts LARGER, which is correct and not a regression:\n harbor evolved-3M-nols-3 82/37h -\u003e 84/39h\n harbor generated 155/128h -\u003e 174/147h\n harbor evolved-3M 131/87h -\u003e 144/100h\n maple generated 126/17h -\u003e unchanged (no missing instances)\n\nNOT taken: the \"one fail per missing instance, placeholders informational\"\noption. It fixes the verbosity dependence too, but silently rescales a missing\nroom from 1/32 to 1/2 -- the same weight as one crinkliness fail. Whether a\nmissing required room SHOULD cost 1/32 is a real question and a separate one;\nbundling it here would have changed the objective's priorities under cover of a\nbug fix. Magnitude left exactly where it was. Filed as a follow-up.\n","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-1i8","title":"Missing-space fail cascade weights rooms by patterns.config verbosity, not by design intent","description":"graph.check_space_counts emits, per missing room instance: 2 base fails ('missing required space: X' + '(critical)') plus one 'would need \u003ccheck\u003e' placeholder for each of size/width/proportion the programme HAPPENS to declare (has_size/has_width/has_proportion are literally 'size' in c etc. from the YAML). So a missing room costs 3 to 5 fails depending only on how many optional keys the author typed. Under value *= 0.5**len(failures) that is a 4x difference in fitness weight between two single rooms. Concretely in programme-house: missing b1 (declares size+width+proportion) = 5 fails = 1/32 penalty; missing t2 (declares size only) = 3 fails = 1/8 penalty. Same for harbor-house: n and cr1 cost 5 each, r and t cost 4 each. The tiered comparator inherits this -- n_hard is dominated by these cascades, so the primary search key is weighted by YAML verbosity.","design":"Either emit exactly one fail per missing instance (and let the cascade placeholders be informational, not counted), or normalise the cascade to a fixed count per instance independent of declared keys. Note this changes every historical fail-count baseline in DESIGN.md, so it needs its own A/B and a recorded re-baseline.","status":"closed","priority":2,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-25T23:15:00Z","created_by":"Claude","updated_at":"2026-08-29T09:33:24Z","closed_at":"2026-08-29T09:33:24Z","close_reason":"Fixed by emitting all three quality placeholders unconditionally (DESIGN.md\n§38.12). A fixed 5 fails per missing instance, independent of how the programme\nwas spelled.\n\nThe decisive evidence is that the two paths disagreed about the same room. A\nPRESENT room is checked on all three qualities regardless of declaration --\nget_space_params fills width and proportion from defaults, deriving width from\nsize when absent, so programme-house's t2 declares `size:` alone and still gets\na real width target of 1.633 it can fail on. Missing, it emitted one placeholder\nwhere b1 emitted three. The cascade stands in for the checks that could not run,\nand it was standing in for the wrong number of them.\n\nCorpus: 36 of 67 codes were under-counted, 31 already at 5. Max weight ratio\nbetween two single rooms goes 4x -\u003e 1x (programme-house), 2x -\u003e 1x (harbor,\nmaple), 1x -\u003e 1x (health-centre, already uniform).\n\nThis makes fail counts LARGER, which is correct and not a regression:\n harbor evolved-3M-nols-3 82/37h -\u003e 84/39h\n harbor generated 155/128h -\u003e 174/147h\n harbor evolved-3M 131/87h -\u003e 144/100h\n maple generated 126/17h -\u003e unchanged (no missing instances)\n\nNOT taken: the \"one fail per missing instance, placeholders informational\"\noption. It fixes the verbosity dependence too, but silently rescales a missing\nroom from 1/32 to 1/2 -- the same weight as one crinkliness fail. Whether a\nmissing required room SHOULD cost 1/32 is a real question and a separate one;\nbundling it here would have changed the objective's priorities under cover of a\nbug fix. Magnitude left exactly where it was. Filed as a follow-up.\n","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"homemaker-py-gvb","title":"Crinkliness is mis-tiered as SOFT, but most crinkliness fails are topological (zero-exposure) and unreachable by the inner loop","description":"fitness._SOFT_FAIL_MARKERS lists ' crinkliness' as SOFT, defined in 37.1 as 'a continuous per-leaf shape metric the inner-loop ratio solve can improve without changing the tree'. That is false for the zero-exposure case: a leaf with no daylit wall cannot be given one by ANY ratio assignment -- it needs a topology change, which is the document's own definition of HARD. Measured share of crinkliness fails that are zero-exposure: harbor-house 60% (36 of 60), maple-court 65% (83 of 127), health-centre 100% (35 of 35); on a converged 20k harbor run, 14 of 17 (82%). Since crinkliness is the single largest fail category (48% of the residual per 13.11), the tiered comparator from 2g7.3 is mis-informed about the largest block of fails it sorts: it tells the search 'these ~40 soft fails are polishable' when two-thirds of them are structurally unreachable, and n_soft is therefore not the polish-budget signal it was designed to be.","design":"Split the crinkliness fail into two strings (or tier it dynamically on area_outside==0) so zero-exposure counts HARD and wrong-ratio counts SOFT. classify_fail_tier is string-based, so the cleanest fix is emitting a distinct fail string for the zero-exposure case -- which also makes the condition visible in .fails output, where today it is indistinguishable from an ordinary shape miss.","acceptance_criteria":"Distinct fail string for zero-exposure; classify_fail_tier maps it HARD; re-run the 37.1 tiered-vs-flat A/B, whose hard/soft split changes materially under the corrected tiering.","status":"open","priority":2,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-25T23:15:00Z","created_by":"Claude","updated_at":"2026-08-25T23:15:00Z","dependencies":[{"issue_id":"homemaker-py-gvb","depends_on_id":"homemaker-py-ssz","type":"blocks","created_at":"2026-08-25T23:15:13Z","created_by":"Claude","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-gvb","title":"Crinkliness is mis-tiered as SOFT, but most crinkliness fails are topological (zero-exposure) and unreachable by the inner loop","description":"fitness._SOFT_FAIL_MARKERS lists ' crinkliness' as SOFT, defined in 37.1 as 'a continuous per-leaf shape metric the inner-loop ratio solve can improve without changing the tree'. That is false for the zero-exposure case: a leaf with no daylit wall cannot be given one by ANY ratio assignment -- it needs a topology change, which is the document's own definition of HARD. Measured share of crinkliness fails that are zero-exposure: harbor-house 60% (36 of 60), maple-court 65% (83 of 127), health-centre 100% (35 of 35); on a converged 20k harbor run, 14 of 17 (82%). Since crinkliness is the single largest fail category (48% of the residual per 13.11), the tiered comparator from 2g7.3 is mis-informed about the largest block of fails it sorts: it tells the search 'these ~40 soft fails are polishable' when two-thirds of them are structurally unreachable, and n_soft is therefore not the polish-budget signal it was designed to be.","design":"Split the crinkliness fail into two strings (or tier it dynamically on area_outside==0) so zero-exposure counts HARD and wrong-ratio counts SOFT. classify_fail_tier is string-based, so the cleanest fix is emitting a distinct fail string for the zero-exposure case -- which also makes the condition visible in .fails output, where today it is indistinguishable from an ordinary shape miss.","acceptance_criteria":"Distinct fail string for zero-exposure; classify_fail_tier maps it HARD; re-run the 37.1 tiered-vs-flat A/B, whose hard/soft split changes materially under the corrected tiering.","status":"open","priority":2,"issue_type":"bug","owner":"noreply@anthropic.com","created_at":"2026-08-25T23:15:00Z","created_by":"Claude","updated_at":"2026-08-25T23:15:00Z","dependencies":[{"issue_id":"homemaker-py-gvb","depends_on_id":"homemaker-py-ssz","type":"blocks","created_at":"2026-08-25T23:15:13Z","created_by":"Claude","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"homemaker-py-57z","title":"Run homemaker-py-2g7.7 acceptance benchmark against evolved-3M-nols-3 plateau seed (needs live ANTHROPIC_API_KEY)","description":"homemaker-py-2g7.7's acceptance criteria requires an end-to-end run of the LLM repair loop against the evolved-3M-nols-3 15-hard-fail plateau seed (level 0 not connected + me1 on wrong level, which survived \u003e1M blind evals / ~2.4 days in the original evolve-3M-nols-3.log run): repair loop reduces hard-fail count within \u003c=20 LLM calls, edit-DSL rejects malformed proposals (should already be covered by unit tests), and an A/B at equal native-eval budget shows strictly better final fails on \u003e=2/3 seeds vs a no-repair control. This requires a live Claude API call (client.messages.create against claude-opus-5) which needs ANTHROPIC_API_KEY set or 'ant auth login' completed -- neither was available in the sandbox that scaffolded the feature (no ANTHROPIC_API_KEY env var, no ant CLI installed). Run this once credentials are available, then close out homemaker-py-2g7.7's acceptance criteria referencing the results.","status":"open","priority":2,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-08-06T07:05:45Z","created_by":"Bruno Postle","updated_at":"2026-08-06T07:05:45Z","dependencies":[{"issue_id":"homemaker-py-57z","depends_on_id":"homemaker-py-2g7.7","type":"blocks","created_at":"2026-08-06T08:06:12Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"homemaker-py-57z","title":"Run homemaker-py-2g7.7 acceptance benchmark against evolved-3M-nols-3 plateau seed (needs live ANTHROPIC_API_KEY)","description":"homemaker-py-2g7.7's acceptance criteria requires an end-to-end run of the LLM repair loop against the evolved-3M-nols-3 15-hard-fail plateau seed (level 0 not connected + me1 on wrong level, which survived \u003e1M blind evals / ~2.4 days in the original evolve-3M-nols-3.log run): repair loop reduces hard-fail count within \u003c=20 LLM calls, edit-DSL rejects malformed proposals (should already be covered by unit tests), and an A/B at equal native-eval budget shows strictly better final fails on \u003e=2/3 seeds vs a no-repair control. This requires a live Claude API call (client.messages.create against claude-opus-5) which needs ANTHROPIC_API_KEY set or 'ant auth login' completed -- neither was available in the sandbox that scaffolded the feature (no ANTHROPIC_API_KEY env var, no ant CLI installed). Run this once credentials are available, then close out homemaker-py-2g7.7's acceptance criteria referencing the results.","status":"open","priority":2,"issue_type":"task","owner":"bruno@postle.net","created_at":"2026-08-06T07:05:45Z","created_by":"Bruno Postle","updated_at":"2026-08-06T07:05:45Z","dependencies":[{"issue_id":"homemaker-py-57z","depends_on_id":"homemaker-py-2g7.7","type":"blocks","created_at":"2026-08-06T08:06:12Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}

View file

@ -2727,6 +2727,9 @@ finish-time `--collapse` (94g) so the comparison is apples-to-apples on the fina
4 workers: 4 workers:
- **harbor-house** (`init.dom`, budget 2500, seeds 13): **ON wins 3/3**, mean fails 80.3 → 72.0 - **harbor-house** (`init.dom`, budget 2500, seeds 13): **ON wins 3/3**, mean fails 80.3 → 72.0
**WITHDRAWN, see §38.21.** Re-measured at n=24 this arm is null (+1.21 fails, p = 0.50,
13W/10L/1T). Harbor's paired σ ≈ 6.2 fails means n=3 could only resolve a margin above ~15,
and 25% of 3-seed subsets show a 3/3 sweep by chance. The default rests on programme-house.
(s1 85→74, s2 76→65, s3 80→77) — a consistent ~10% fail reduction, no losses. (s1 85→74, s2 76→65, s3 80→77) — a consistent ~10% fail reduction, no losses.
- **programme-house** (`init.dom`, budget 3000, seeds 15): ON wins 3/5, mean fails 8.4 → 7.8 - **programme-house** (`init.dom`, budget 3000, seeds 15): ON wins 3/5, mean fails 8.4 → 7.8
(s1 8→5, s2 8→7, s4 10→9 win; s3 8→9, s5 8→9 loss by one fail) — a weaker, noisier signal on (s1 8→5, s2 8→7, s4 10→9 win; s3 8→9, s5 8→9 loss by one fail) — a weaker, noisier signal on
@ -5978,6 +5981,59 @@ independent reason §37.7 gives, and this reinforces it. What changes is that th
"cpsat wins the seeder A/B" claim should no longer be cited as a reason to "cpsat wins the seeder A/B" claim should no longer be cited as a reason to
pursue it. pursue it.
### 38.21 Harbor A/Bs at n=3 could never have resolved their own margins (`homemaker-py-0wr`)
`0wr` asked which harbor results decided by a narrow margin should be
re-checked after §39.4. Measuring harbor's actual variance answers a broader
question than the issue posed.
**Harbor's paired seed-to-seed spread is σ ≈ 6.2 fails** (24 paired ON/OFF runs,
budget 2500). At n=3 that gives a **minimum detectable difference of ~15.4
fails**. Every recorded harbor margin is below it:
| section | harbor margin | resolvable at n=3? |
|---|---|---|
| §13.9 `share_edge_cap` | 34.7 → 31.0 = 3.7 | no |
| §20 `qpk` collapse | 80.3 → 72.0 = 8.3 | no |
| §23 `f1d` ruin-recreate | mixed (1W/1L/1T) | no |
| §37.1 tiering | hard 11.67 → 5.33 = 6.3 | no |
| §17 `94g` | byte-identical | n/a — no margin claimed |
So the finding is not "some harbor results were narrow". It is that **no harbor
A/B run at three seeds could resolve the margin it reported**, whatever §39.4
did to the programme. Of the 220 possible 3-seed subsets of the 24 measured
below, **56 (25%) show a clean 3/3 sweep for ON** — a 3/3 result on this
programme is close to a coin-flip artefact, not evidence.
**§20's harbor arm, re-measured.** Same protocol (budget 2500, ON vs OFF, both
finished with `--collapse`), taken to n=24:
| N | OFF | ON | W/L/T | mean diff | p | 95% CI |
|---|---|---|---|---|---|---|
| 3 | 92.00 | 89.33 | 2/1/0 | +2.67 | 0.560 | [13.87, +19.21] |
| 12 | 92.75 | 89.25 | 8/3/1 | +3.50 | 0.076 | [0.43, +7.43] |
| **24** | 88.92 | 87.71 | 13/10/1 | **+1.21** | **0.502** | **[2.46, +4.88]** |
**Null.** 13W/10L/1T is a coin flip, and the CI comfortably spans zero. The
published "harbor-house: ON wins 3/3, mean 80.3 → 72.0" was a lucky draw — note
even seeds 13 measured here give 2W/1L, not a sweep. (Absolute levels differ
from the published ones because the objective has changed; the ON/OFF comparison
within this measurement is like-for-like.)
**Consequence for the `collapse_insearch` default.** §20 concluded "the qpk
verdict holds at **both** example scales tested". That claim is **withdrawn**
harbor is null at adequate N. What survives is §38.19's programme-house result
(N=60, +0.57 fails/seed, p = 0.017, Wilcoxon 0.014). The default stands on one
programme, not two. It is not refuted on harbor either — the direction is
positive, just indistinguishable from zero — but harbor should no longer be
cited as corroboration.
**The standing lesson.** Combined with §38.19, where programme-house needed N=60
to resolve an effect its own protocol claimed at N=20: *harbor at n=3 resolves
nothing finer than ~15 fails, and programme-house at N=20 resolves nothing
finer than ~1 fail.* Any future A/B on these programmes should state its
detectable difference before running, not after.
## 39. Config audit: requirements that actively fight the engine (`homemaker-py-ju3`) — measured 2026-08-25 ## 39. Config audit: requirements that actively fight the engine (`homemaker-py-ju3`) — measured 2026-08-25
The corpus `patterns.config` targets and `costs.config` values were estimated The corpus `patterns.config` targets and `costs.config` values were estimated

View file

@ -1,17 +1,19 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Re-run the 1ph protocol (DESIGN.md §20): programme-house init.dom, budget 3000, # Re-run the 1ph protocol (DESIGN.md §20): programme-house init.dom, budget 3000,
# 4 workers, ON vs OFF, BOTH arms finished with --collapse. # 4 workers, ON vs OFF, BOTH arms finished with --collapse.
# Usage: rerun_1ph_protocol.sh <worktree> <tag> <out.tsv> [lo] [hi] (APPEND=1 to add) # Usage: rerun_1ph_protocol.sh <worktree> <tag> <out.tsv> [lo] [hi]
# env: PROG (default programme-house), BUDGET (3000), WORKERS (4), APPEND=1
set -u set -u
W="$1"; TAG="$2"; OUT="$3"; LO="${4:-1}"; HI="${5:-20}" W="$1"; TAG="$2"; OUT="$3"; LO="${4:-1}"; HI="${5:-20}"
cd "$W/examples/programme-house" PROG="${PROG:-programme-house}"; BUDGET="${BUDGET:-3000}"; WORKERS="${WORKERS:-4}"
cd "$W/examples/$PROG"
[ "${APPEND:-0}" = "1" ] || : > "$OUT" [ "${APPEND:-0}" = "1" ] || : > "$OUT"
for seed in $(seq "$LO" "$HI"); do for seed in $(seq "$LO" "$HI"); do
for arm in on off; do for arm in on off; do
flag=""; [ "$arm" = "off" ] && flag="--no-collapse-insearch" flag=""; [ "$arm" = "off" ] && flag="--no-collapse-insearch"
t0=$(date +%s) t0=$(date +%s)
PYTHONPATH="$W/src" timeout 600 python -m homemaker_layout.evolve init.dom \ PYTHONPATH="$W/src" timeout 600 python -m homemaker_layout.evolve init.dom \
--budget 3000 --seed "$seed" --workers 4 --collapse $flag \ --budget "$BUDGET" --seed "$seed" --workers "$WORKERS" --collapse $flag \
--output "$OUT.$arm.dom" > "$OUT.$arm.log" 2>&1 --output "$OUT.$arm.dom" > "$OUT.$arm.log" 2>&1
t1=$(date +%s) t1=$(date +%s)
n=$(PYTHONPATH="$W/src" python - "$OUT.$arm.dom" <<'PY' n=$(PYTHONPATH="$W/src" python - "$OUT.$arm.dom" <<'PY'

View file

@ -0,0 +1,48 @@
harbor 1 on 96 52
harbor 1 off 103 24
harbor 2 on 81 53
harbor 2 off 76 25
harbor 3 on 91 55
harbor 3 off 97 26
harbor 4 on 99 54
harbor 4 off 91 25
harbor 5 on 82 54
harbor 5 off 82 25
harbor 6 on 90 53
harbor 6 off 95 25
harbor 7 on 88 55
harbor 7 off 87 25
harbor 8 on 90 53
harbor 8 off 100 27
harbor 9 on 87 53
harbor 9 off 98 26
harbor 10 on 86 55
harbor 10 off 97 26
harbor 11 on 79 56
harbor 11 off 84 25
harbor 12 on 102 52
harbor 12 off 103 26
harbor 13 on 93 53
harbor 13 off 98 24
harbor 14 on 77 53
harbor 14 off 83 25
harbor 15 on 76 53
harbor 15 off 75 26
harbor 16 on 102 56
harbor 16 off 87 26
harbor 17 on 78 55
harbor 17 off 89 27
harbor 18 on 89 54
harbor 18 off 83 26
harbor 19 on 102 53
harbor 19 off 82 24
harbor 20 on 72 51
harbor 20 off 74 26
harbor 21 on 89 54
harbor 21 off 82 24
harbor 22 on 84 54
harbor 22 off 80 25
harbor 23 on 91 53
harbor 23 off 90 26
harbor 24 on 81 53
harbor 24 off 98 27
1 harbor 1 on 96 52
2 harbor 1 off 103 24
3 harbor 2 on 81 53
4 harbor 2 off 76 25
5 harbor 3 on 91 55
6 harbor 3 off 97 26
7 harbor 4 on 99 54
8 harbor 4 off 91 25
9 harbor 5 on 82 54
10 harbor 5 off 82 25
11 harbor 6 on 90 53
12 harbor 6 off 95 25
13 harbor 7 on 88 55
14 harbor 7 off 87 25
15 harbor 8 on 90 53
16 harbor 8 off 100 27
17 harbor 9 on 87 53
18 harbor 9 off 98 26
19 harbor 10 on 86 55
20 harbor 10 off 97 26
21 harbor 11 on 79 56
22 harbor 11 off 84 25
23 harbor 12 on 102 52
24 harbor 12 off 103 26
25 harbor 13 on 93 53
26 harbor 13 off 98 24
27 harbor 14 on 77 53
28 harbor 14 off 83 25
29 harbor 15 on 76 53
30 harbor 15 off 75 26
31 harbor 16 on 102 56
32 harbor 16 off 87 26
33 harbor 17 on 78 55
34 harbor 17 off 89 27
35 harbor 18 on 89 54
36 harbor 18 off 83 26
37 harbor 19 on 102 53
38 harbor 19 off 82 24
39 harbor 20 on 72 51
40 harbor 20 off 74 26
41 harbor 21 on 89 54
42 harbor 21 off 82 24
43 harbor 22 on 84 54
44 harbor 22 off 80 25
45 harbor 23 on 91 53
46 harbor 23 off 90 26
47 harbor 24 on 81 53
48 harbor 24 off 98 27