Commit graph

215 commits

Author SHA1 Message Date
Claude
024311a2c2
§39.10: preserving constructed connectivity is NULL — and it reframes §39.9
§39.9 named the upstream fix: keep circulation connected DURING the resize
rather than rebuilding it after. Built and measured. It does not help, and the
reason matters more than the lever.

Both halves of the re-cut do damage, in different proportions per programme.
Freezing rotations and letting only ratios move (% levels connected, 12 seeds):
harbor 100 -> 71 -> 50, health-centre 100 -> 8 -> 8, maple 100 -> 92 -> 67. So
health-centre is destroyed entirely by the ratio and maple mostly by the
rotation; a fix must be able to give back either.

operators._size_divisions_preserving_circulation snapshots every cut, resizes,
then reverts the cuts on the tree path between each circulation pair the resize
broke -- programme fully intact, no retyping, only geometry given back. It works
on connectivity (harbor 50->92%, maple 67->97%, health-centre 8->17%) and costs
area accuracy: constructed-seed fails harbor 96.6->141.5, maple 141.8->175.8,
size fails roughly double. (A greedy single-cut revert barely moved -- it stalls
where no ONE revert helps though two would. Targeting the broken pairs is what
made connectivity work.)

The obvious defence -- raw constructed seeds understate it, the resize is only a
warm start, the inner loop should recover -- was TESTED AND FAILS. Full search,
harbor-house, 12000 evals, seed 1:
  OFF  43 fails,  9 hard, 3 connectivity
  ON   65 fails, 26 hard, 4 connectivity
Worse on every axis, including connectivity itself.

REFRAMING: §39.9's fact stands (the resize destroys 41 of 49 circulation edges)
but is NOT ACTIONABLE, because construction-time connectivity does not determine
final connectivity. The search discards and rebuilds the seeder's circulation
either way, and constraining the seed only spends area quality the search cannot
recover. Together with §39.8 (not an incentive problem) that retires the framing
this thread inherited from §38: connectivity is neither a construction problem
nor an incentive one.

Both flags (repair_circulation, preserve_circulation) stay default off with the
numbers recorded, plus byte-identical-default tests. Do not revisit either
without a new formulation -- the standing this document gives bubble.py.

356 passed (+1 new), 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
2026-08-26 15:11:46 +00:00
Claude
7c41069226
§39.9: level-not-connected is destroyed by the resize, not by the search
Answers homemaker-py-yql. §39.8 established the search is not PAID to sever
circulation; this establishes where connectivity actually goes.

CONSTRUCTED, THEN LOST -- at construction time, in the resize.
_assign_adjacency_aware picks circulation as a CONNECTED dominating set and
succeeds every time. _size_divisions_from_targets then moves every wall to hit
the programme's area targets and destroys it.

Measured over 20 constructed seeds per programme, fully-connected seeds:
harbor-house 1/20, health-centre 1/20, maple-court 0/20. The control -- same
seeds with proportion_aware=False, i.e. no resize -- is 100% connected on all
three. Mechanism confirmed on health-centre: 41 of 49 circulation-to-circulation
edges destroyed by the resize, surviving shared walls squeezed to 0.54-1.11 m
against door_width=1.2, so they stop counting as edges. This is the failure mode
§37.7 recorded for CP-SAT assignment, never looked for in connectivity, where it
costs 35-95 points.

§39.7 COST CHECK: zero. Identical rates under prefix-inferred vs declared
usages -- has_circulation never trims C-C edges, so last commit's usage change
could not and did not make connectivity harder to achieve.

REPAIR MEASURED NEGATIVE. operators.repair_circulation_settled applies §37.7's
own alternating-minimisation fix (re-connect against the settled geometry by
retyping the cheapest bridging leaves to C). It restores 100% connectivity on
all three programmes -- and is still the wrong trade: connectivity fails fall
0.8-1.7 per seed while missing-room fails rise 5.0-8.5, because every retyped
leaf displaces a required room at a 3-5 fail cascade (§38.5). Kept default off
with the write-up, per house style for a null lever, plus a byte-identical
default test and a test asserting it does reconnect every storey.

NEXT LEVER, FILED: preserve the connection during the resize (constrain
_size_divisions_from_targets so a shared C-C boundary cannot fall below
door_width) rather than rebuild it afterwards at the programme's expense --
a constraint on an existing solve, not a new repair pass. solver.py's existing
min_width_generic is the same idea applied to leaf width rather than to a shared
boundary, so it may belong beside it.

Adds experiments/diag_connectivity_yql.py (construct / cost / survive reports).
355 passed (+2 new), 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
2026-08-26 14:39:07 +00:00
Claude
3aee813ccd
§39.8: homemaker-py-2v1 connectivity weighting — MEASURED NULL, premise retracted
§38.2 concluded the objective is net-positive on severing a level's
circulation: merging a corridor into a habitable sibling gains x6
(value_inside/value_circulation), while "level N not connected" costs x0.5, so
break-even needs 0.5^w < 50/300, w > 2.58 -- "severing must cost at least 3
fails and costs 1". The arithmetic is right. The premise is wrong.

Shipped anyway, EXPERIMENTAL and default off (byte-identical):
fitness.connectivity_weight_for(value_inside, value_circulation) returns the
smallest weight making severing net-negative -- 3.0 at the defaults, DERIVED
from the rates rather than hard-coded so it tracks them if either is retuned.
conf["connectivity_weight"] takes 1.0 / "auto" / a number and counts each
connectivity failure as w failures in the 0.5^n penalty.

MEASUREMENT: at auto (=3) the §38.2 deletion test does not move at all -- 5/25
rewarded either way, median x0.26 vs x0.27. Reason: the connectivity fail count
is UNCHANGED in every rewarded deletion (115->107 fails but 5->5 connectivity;
107->99 but 3->3; 78->71 but 3->3). Weighting a fail that never fires changes
nothing.

And when a deletion DOES break connectivity, it is already punished. Every such
case, 4 seeds per programme: harbor-house 2 of 32 sampled deletions, both
punished (x0.00, x0.01); maple-court 5 of 32, all punished (x0.58 .. x0.07).
Severing costs 1-2 connectivity fails PLUS the cascade after them, which
already outweighs the x6 gain. The flat rule was never the problem.

Where §38.2 went wrong: the x4.06 "well-daylit circulation leaf" that motivated
the bead was a deletion that did NOT change the connectivity fail count. It was
rewarded for removing the leaf's own quality failures -- §38.1's zero-value
finding -- and I misread it as a pricing mechanism. §38.2 now carries the
retraction inline. Two lessons recorded: a plausible closed-form arithmetic is
not a measurement, and when a fix produces exactly no effect, suspect the
premise before the implementation.

Still standing from §38: §38.1 (buried leaves score zero quality and contribute
no value) and §38.3 (frontage budget) are direct measurements. §39.7 remains
the better lever on the same symptom -- it made the connectivity fails FIRE,
where this would only have made them cost more.

Re-opened as homemaker-py-yql: why level-not-connected persists in the best
layout when severing is already punished. Evidence now points at reachability,
not incentive, and it is newly measurable because §39.7 stopped store cupboards
standing in for corridors.

353 passed (+3 new), 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
2026-08-26 14:15:22 +00:00
Claude
03aadec1ba
§39.7: access requirements become a declared usage: attribute (homemaker-py-sel)
Closes the second namespace sharing a first character with programme codes: the
usage prefixes b/t/l/k, under which a room silently inherited another room's
connectivity rules from its spelling.

usage is a plain, MANDATORY attribute of the space definition -- not a lookup
table. An interim design proposed a top-level usage_classes: table binding
author-coined names to behaviour; withdrawn, because an indirect name->behaviour
mapping living apart from the thing it describes is exactly the shape of the
prefix rule §39 exists to remove, it would be the only such table in a schema
where every other space property is a plain attribute, and the need it served
was already met -- "building specific" is about what a room is CALLED, and
name: is already free text.

Rule that settles it: a usage value exists iff the engine treats it differently
somewhere. Config selects among behaviours; it cannot invent them.

- programme.USAGES (living/kitchen/bedroom/toilet/utility/none) plus the
  behaviour groupings PRIVATE_USAGES / PRIVATE_STRIPS / TOILET_STRIPS /
  SOCIABLE_USAGES. Missing or unknown usage is a load error naming the code,
  from BOTH parse paths.
- Code-level, never leaf-level: usage_of(leaf.type) is looked up fresh, so a
  retype changes the class automatically. 51 sites assign leaf.type, and
  share/share_type plus the r5a resurrection are the precedent for why
  leaf-level attributes rot.
- graph.has_circulation takes the usage map and trims on declared class;
  fitness.access and the public-access check likewise. fitness._t0 is DELETED --
  no first-character type test remains anywhere in the codebase.
- utility is distinct from bedroom (same access requirements today) because it
  is a different use and gives derive_interchange_classes an axis to relax on.
- A toilet now keeps its edge to a terminal room -- the Brand adjacency, which
  the old b-before-t loop ordering severed.
- All 107 corpus entries migrated by experiments/migrate_usage_key.py, comments
  and layout preserved.

MEASURED -- the connectivity model was ~4x too permissive. `none` is not
neutral: nothing is trimmed, so the graph may route THROUGH the room, and 34 of
52 codes had no class (Dental Surgery, Records Room, Utilities Closet all served
as corridors). Edges trimmed, prefix-inferred vs declared, 3 seeds each:
  harbor-house   18 (9%)  -> 79 (39%)   inaccessible fails 0 -> 4
  health-centre  12 (8%)  -> 59 (40%)   inaccessible fails 2 -> 3
  maple-court    53 (17%) -> 123 (39%)  inaccessible fails 1 -> 5

Re-baseline (seed 1, 20k, harbor): 58 fails (15h/43s) -> 61 (16h/45s), now
reporting 1-inaccessible-usable-space x2 plus level 0 and level 1 not connected.
The count rose because the objective got honest -- those failures were always
true of the layout and the old model could not see them. Every harbor number
before this was measured against a graph crediting routes through store
cupboards.

Sharpens §38.2: the objective pays x60-85 to delete circulation, and until now
the deleted corridors were not missed because storage stood in for them. With
that substitution gone, homemaker-py-2v1 is the remaining half -- and now
measurable, because the fails it should prevent actually fire.

350 passed (+5 new), 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
2026-08-26 13:39:41 +00:00
Claude
72673a2ebf
homemaker-py-sel: usage is a plain space attribute — drop the mapping table
The proposed top-level `usage_classes:` table (binding author-coined names to
engine behaviour, e.g. craft -> living) is withdrawn. Wrong three ways:

a) Same bug in another costume. An indirect name -> behaviour mapping living
   apart from the thing it describes is exactly the shape of the
   first-character prefix rule. §39 exists to remove that shape, not relocate
   it into a table.

b) Inconsistent with the schema. Every other space property is a plain
   attribute -- name, size, width, proportion, adjacency, level,
   requires_below, count, share, interchange, co_locate -- and no key anywhere
   in patterns.config is an indirection table. Verified across the corpus.

c) The need was already met. "Programmes are building specific" is about what a
   room is CALLED, and name: is already free text. usage: records ACCESS
   REQUIREMENTS, which are not building-specific -- a craft room and a lounge
   have the same ones, which is the entire reason the key exists. The earlier
   draft conflated the two.

So: spaces: ws1: {name: Workshop Space, usage: living} -- one place, no
binding step, no unbound-name error class.

Rule that falls out and is worth keeping: A USAGE VALUE EXISTS IF AND ONLY IF
THE ENGINE TREATS IT DIFFERENTLY SOMEWHERE. Config selects among behaviours; it
cannot invent them. An alias produces no behaviour that the aliased value does
not. `utility` passes the test -- not on edge-stripping, which is identical to
bedroom today, but because it is intended to drive derive_interchange_classes.

No src changes; proposal file only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 12:56:12 +00:00
Claude
d5e10172c5
homemaker-py-sel: all 52 corpus codes assigned; utility distinct; open vocabulary
Rulings settle every previously-unresolved code: zt1 Sterilisation -> utility;
ph1 Pharmacy -> bedroom (a private room, not public, like an office); n
"Neighborhood" -> bedroom (a communal sleeping area, much like a dormitory);
gh1 Greenhouse -> living (grows plants, but a living area like a conservatory);
ws1 Workshop -> living conditionally, since it is building-specific (communal
craft room vs maintenance area) and both corpus programmes carrying it are
communal living facilities.

Final: living 12, bedroom 17, utility 11, toilet 7, kitchen 2, none 3. Zero
unresolved, zero missing.

DESIGN 1 — `utility` is a distinct value, not an alias for `bedroom`. Same
edge-stripping today (identical access requirements) but separately declared,
because they are very different uses AND because it gives
programme.derive_interchange_classes (§13/§26, homemaker-py-9o5) a natural
axis: bedroom- and utility-class leaves could be interchangeable DURING search
and collapse to their real use at scoring time, which is exactly the
superposition relaxation that machinery already implements.

DESIGN 2 — vocabulary controlled but NOT closed. The earlier "closed enum,
unknown value errors" recommendation is withdrawn. The six known names drive
behaviour; a programme may coin its own (`usage: craft`) provided it binds it
in the same file via `usage_classes: {craft: living}`. An unbound name is a
load error, so naming stays building-specific without an unrecognised usage
ever falling through to a silent default.

VERIFIED — the Brand adjacency point is not an engine bug. check_adjacency runs
against graph_base_pre, the UNFILTERED graph, so a declared adjacency is
satisfied by a neighbouring room regardless of what has_circulation strips; the
stripping only denies routing, which is correct. "A toilet adjacent to a
bedroom is a positive even if there is no door" is therefore already
expressible -- but only where DECLARED, and just one corpus programme declares
it (programme-house t1 -> [b1]). harbor-house, maple-court and health-centre
leave that adaptability credit on the table. Filed separately; it is programme
authoring and can land before or after the usage key.

No src changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 12:34:03 +00:00
Claude
6bed7cc535
homemaker-py-sel: propose usage for all 52 corpus codes; scope was understated
Bruno's rulings settle the framing: usage is an ACCESS-REQUIREMENT class, not a
room-name category. li1 "Library Corner" and br1 "Staff Room" are living rooms
(same access requirements); tr1 "Treatment Room" has a bedroom's requirements
(terminal, not a circulation route); la1 "Laundry Room" is utility. Ground-floor
external cases (fuel stores, bins) need no class — level: 0 plus adjacency: [o]
already expresses that.

SCOPE CORRECTION. My "93% pure annotation, 7 entries change" estimate was
mechanically true but misleading: `none` is not neutral. Nothing is stripped, so
has_circulation MAY ROUTE THROUGH the room. 34 of 52 distinct corpus codes
currently have no usage class and are therefore modelled as permeable corridors
-- including Dental Surgery, GP Consulting, Minor Surgery, Physiotherapy,
Counselling, Records, Sterilisation, six storage rooms, four offices and
"Individual Room" (a resident's own room).

Consequence for §38: the model OVERSTATES connectivity, since a level can be
found connected through rooms that are dead ends in reality. "level N not
connected" is therefore rarer than it should be, compounding §38.2 -- the
objective already pays x60-85 to delete circulation, and the corridors it
deletes are then not missed because store cupboards stand in for them.

Adds experiments/usage_map_proposal.yaml: all 52 codes covered (47 assigned, 5
unresolved, 0 missing) -- living 10, kitchen 2, bedroom 15, toilet 7, utility
10, none 3. Nothing reads it yet; it is the review artifact and, once agreed,
the migration input.

Also verified and recorded (Q2): a dedicated toilet off a bedroom-class room
does NOT survive scoring. has_circulation runs its bedroom loop before its
toilet loop and the bedroom loop strips bedroom->toilet, so the ensuite is
severed -- for real bedrooms too. Existing Urb behaviour, neither caused nor
fixed by the usage key.

No src changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 10:47:11 +00:00
Claude
f476a5849e
beads: revise homemaker-py-sel design — mandatory code-level usage, no fallback
Records the outcome of the "how does a parallel usage key work when the leaf
name can mutate?" review. Two problems were conflated:

1. Mutation staleness dissolves if usage is CODE-level: usage_of(leaf.type) is
   looked up fresh, exactly as size/width/proportion/adjacency already are.
   Verified every corpus leaf type resolves to a declared code or a generic.
   The broken design is usage stamped ON THE LEAF — 51 sites assign leaf.type,
   and this project already hit that class twice (share needed a companion
   share_type; r5a was a real stale-stamp resurrection even with the guard).

2. Name/key divergence is real and is NOT fixed by (1). Resolved by making
   usage mandatory on every declared code with no prefix fallback, closed
   vocabulary {bedroom, toilet, living, kitchen, none}, missing key = load
   error. One source of truth; room codes become free-form identifiers.

Measured migration: 10 files, 107 entries, 100 (93%) pure annotation; only 7
change behaviour (la1 x3, li1 x2, br1, tr1) and those are the fix.
write_stage1_programme already propagates the key.

Left open as the programme author's call, not mechanical: what those four
rooms should declare — li1 "Library Corner" as living is arguably already
correct, and br1 "Staff Room" may want living rather than none. Also noted:
mandatory breaks out-of-repo configs until annotated (mitigate with an error
naming each code and its prefix-implied usage, plus a migration script), and
the 7 changed entries need their own A/B and re-baseline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 10:32:14 +00:00
Claude
a25dc2cb59
§39.4 completion + §39.5 retraction + §39.6: the usage namespace is NOT clean
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
2026-08-26 10:09:14 +00:00
Claude
7ec4e5d121
§39.4: tighten generic-type matching, reverting the harbor rename
Supersedes the previous commit's approach. Renaming harbor's four colliding
codes fixed one programme; tightening the matching rule fixes the rule, so a
room may be called anything. cr1/of/st1/st2 are restored and the examples are
byte-identical to their pre-§39 state -- which also means existing .dom
artefacts (evolved-3M*) stay valid, so migrate_ju3_rename.py is deleted.

The rule: Urb has exactly three GENERIC structural types (get_space_types:
qw/C O S/), the leaves the search creates. Measured across the corpus: 154 C,
110 O, 1 S, not one lowercase generic -- while every programme code is
lowercase, including single-character ones (r, t, m, n). Case is the
discriminator, not length. Every generic test was type[0].lower() in (...), a
case-insensitive PREFIX that swept up any programme code starting with those
letters; they now match the generic set exactly. 30 sites across dom, fitness,
graph, operators, programme, shapecurve and bubble.

NOT applied to the SEMANTIC prefixes: l/k/b/t classify programme codes by first
letter (graph.py builds bedroom<->toilet and kitchen<->living relations from
them) and stay prefix-based. Where the namespaces were mixed in one expression
they were split -- has_circulation's ("b","l","k","c") is three semantic
prefixes plus dom.is_circulation; access()'s ("l","c","s") is semantic l plus
the generic circulation set.

New: dom.GENERIC_{CIRCULATION,OUTSIDE,TYPES} + is_generic(); fitness.
_generic_class(), replacing the _t0 dispatch in quality_size/quality_width/
quality_proportion/value_rate -- the four terms that mattered most and that a
first sweep missed, since they dispatch through a t0 variable rather than an
inline test. graph._adjacency_target resolves a generic adjacency requirement
(programmes write "adjacency: [c, o]") to the generic set while every other
requirement keeps Perl's prefix semantics.

Two subtleties: S is in both generic sets but takes the OUTSIDE parameter
families -- a first translation tested circulation first and silently gave S
the circulation params, caught by test_get_space_params_sahn_proportion. And
validate_codes survives, narrowed to a code spelled exactly C/O/S, which is a
genuine ambiguity; merely starting with c/o/s is now fine.

Invariant asserted as a test: test_scoring_is_invariant_under_programme_code_
spelling relabels one tree and its config together and re-scores. Bit-identical
across 12 comparisons (6 seeds x collapse on/off).

Re-baseline (seed 1, 20k, original names): 58 fails (15 hard / 43 soft) against
the real 37-instance programme, with cr1 at 79.1 m2 vs declared 80 (was 32.9
and 17.1), of/st1/st2 all present and in band, and one fail naming any of them.
57 -> 58 on a 5-instance-harder programme is within noise: "did not regress".

Fallout (§39.5): 2g7.5's CP-SAT seeder win does not survive. Over 6 seeds --
harbor real 102/114 (cpsat loses), harbor old-effective 98/99 (tie, so the win
was already marginal), maple-court 156/144 (cpsat wins). maple is the control:
the solver did not regress, harbor's programme changed. Test xfail'd with that
reason plus a maple companion; both assign_solver flags stay default off.
Filed homemaker-py-w6x to re-check other narrow-margin harbor A/Bs.

345 passed, 1 xfailed, same 7 pre-existing fixture failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 09:45:28 +00:00
Claude
697914fac8
ju3: reject programme codes colliding with the c/o/s generic type prefixes
Closes homemaker-py-ju3. DESIGN.md §39.3.

The class: key from the bead's design was deliberately NOT built. Auditing
every use of the prefix rule first showed it runs deeper than c/o/s -- l/k/b/t
carry real adjacency semantics (graph.py builds bedroom<->toilet and
kitchen<->living relations from first characters) -- so re-plumbing the type
system would invalidate the whole corpus and every baseline, for a problem
whose damage is the silence, not the convention. Two findings made the smaller
fix sufficient: no corpus programme has ever declared a bare c/o/s code, so
check_space_counts' skip only ever discarded declared rooms; and nothing
references harbor's four codes in any adjacency or co_locate list.

- programme.validate_codes raises on a reserved-prefix code, with the full
  explanation. Called from BOTH parse paths (programme._parse_spaces and
  fitness.Fitness._load_programme parse conf["spaces"] independently, so
  validating one would leave the other door open). l/k/b/t stay unreserved.
- harbor-house and harbor-house-l0 renamed: cr1->fr1, of->ao, st1->gs1,
  st2->gs2. New prefixes are unused in harbor and semantically neutral, and
  the two storage codes still share a prefix, preserving the structure
  evaluate_building's per-code plot-ratio term depends on. name: unchanged.
- experiments/migrate_ju3_rename.py migrates .dom files written before the
  rename (--check dry-runs). Pre-rename artefacts, notably evolved-3M*.dom,
  must be migrated or their leaves read as unmatched generics.
- test_collapse_global's c/o/s exclusion test now uses a generic C leaf, which
  is what the exclusion is actually for; it previously relied on a programme
  code colliding, which is no longer possible.

Re-baseline (seed 1, 20k evals, same settings as §38's run): 57 fails against
the 32-instance effective programme -> 55 against the real 37-instance one,
with all five previously-lost room instances now placed inside their declared
sigma bands (fr1 87.2 vs declared 80, was 32.9/17.1; ao/gs1/gs2 were absent
entirely) and no failure naming any of the four codes. At one seed each,
57 vs 55 is within noise -- the robust result is the room placement, not the
count. Historical harbor numbers are not comparable to post-ju3 ones; filed
homemaker-py-t3s to restate 2v1's acceptance figure once evolved-3M is
migrated.

346 passed (+10 new), same 7 pre-existing fixture failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 09:06:08 +00:00
Claude
fd9802e499
DESIGN.md §39: config audit — programme codes collide with the c/o/s type namespace
Answers "are any config requirements actively fighting the engine". One is.

§39.1 NEGATIVE (recorded): no room spec in any corpus programme is internally
contradictory. Using shapecurve.leaf_constraints' validated FAIL_THRESHOLD
inversions, every code admits an (area, aspect) satisfying size, width,
proportion and crinkliness at once, and none needs more than one exposed side.
The "estimated targets are mutually unsatisfiable" hypothesis is falsified.

§39.2 SEVERE: Urb's type system is prefix-based (c = circulation, o/s =
outside) and programme codes share that namespace. A code starting with those
letters is silently reinterpreted, with three unannounced consequences:
check_space_counts SKIPS it outright (never required, no missing or too-many
fail); get_space_params returns generic *_circulation/*_outside params before
consulting self.spaces; and is_circulation/is_outside flip, changing value
rate, crinkliness exemption, and whether it supplies daylight to neighbours.

harbor-house is affected (maple-court, health-centre, programme-house are
clean): cr1 "Common Room with Fireplace" has all three declared targets
overridden (size 80.0 -> 0.0/14.0) and is valued at 50/m2 not 300; of x2 and
st1/st2 lose width/proportion and are treated as outside space. 5 of 37 room
instances (14%) are silently optional.

Measured: the two cr1 leaves converged to 32.9 and 17.1 m2 against a declared
80, with no too-many-spaces fail despite count:1; of/st1/st2 are absent from
the result with zero fails. Compounds with §38.2 -- the largest room in the
programme sits on the wrong side of the x6 circulation value gap, so the
objective is paid to shrink it.

Benchmark validity: every harbor-house fail count in this document was
measured against a 32-instance effective programme, not the 37 its config
declares.

Adds experiments/audit_programme_config.py (namespace + satisfiability
reports). Filed homemaker-py-ju3 (P0). No src changes; 336 passed, same 7
pre-existing fixture failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 08:27:49 +00:00
Claude
1b3a0adc2e
beads: file homemaker-py-2v1 (connectivity mispricing, P0)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-26 07:40:37 +00:00
Claude
753356e47e
beads: file §38 objective-gradient findings
homemaker-py-ssz  (P1) zero-exposure leaves score hard quality=0
homemaker-py-hxi  (P1) buried circulation/outside are negative-value
homemaker-py-tdp  (P1) frontage-budget feasibility bound
homemaker-py-gvb  (P2) crinkliness mis-tiered as SOFT
homemaker-py-1i8  (P2) missing-space cascade weighted by config verbosity
homemaker-py-bdf  (P3) fresh-clone test failures from absent evolved-3M fixtures

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-25 23:18:47 +00:00
Claude
7046c7bd76
Ignore beads auto-import tracking marker
.auto-import-issues.jsonl is a per-machine mtime/size cache bd writes
when auto-importing issues.jsonl; it shouldn't be versioned.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJ84Feep79Hhm3E4zZJmnB
2026-08-25 23:01:40 +00:00
25e0503ddc bd: sync issues.jsonl export after 8oq/57z creation
Created homemaker-py-8oq (review the 2g7.7 LLM-repair plan with a more
capable model) and homemaker-py-57z (live acceptance-benchmark follow-up,
blocked on ANTHROPIC_API_KEY availability), linked as blockers/dependents
of homemaker-py-2g7.7 per the planning session on 2026-08-05.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uCyZJCh5mBuA2yEFxgQpo
2026-08-06 08:08:07 +01:00
91f7626a77 bd: close homemaker-py-pek
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uCyZJCh5mBuA2yEFxgQpo
2026-08-05 16:59:25 +01:00
5f5e640906 DESIGN.md sec 13.11: correct stale 7ua note, cross-ref follow-up 4ok
homemaker-py-7ua is fixed but only covers run_staged_search.py's
LEAFSHARE/MULTIUSE-gated rescore path. Baseline (LEAFSHARE=0/MULTIUSE=0)
runs still MISMATCH for the same underlying reason -- driver.search_staged
has no collapse_insearch param and always runs with it on -- tracked as
the new homemaker-py-4ok.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uCyZJCh5mBuA2yEFxgQpo
2026-08-05 13:54:42 +01:00
88f36177bb homemaker-py-7ua: pin collapse_insearch=True in run_staged_search.py rescore
driver.search_staged has no param to disable collapse_insearch, so its
inner evaluator always runs with search()'s collapse_insearch=True
default. The final _native_score() sanity rescore loaded patterns.config
fresh with no override, so it silently diverged from search-time conf
whenever leaf_sharing was on, producing a false MISMATCH. Verified with
a smoke run: pre-fix MISMATCH, post-fix OK with identical scores.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uCyZJCh5mBuA2yEFxgQpo
2026-08-05 10:08:04 +01:00
5af8827a10 bd: sync issues.jsonl export after sd3 close
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uCyZJCh5mBuA2yEFxgQpo
2026-08-05 07:55:02 +01:00
35adcd4b4d homemaker-py-sd3: fix vacuous 94g keep-better guard (collapse_insearch leak)
driver.collapse_best built its evaluator with _fitness_for's default
collapse_insearch=True, so collapse_finish's base_fails/cand_fails were
both measured through score_with_fails' own auto-collapse pass -- base
silently equalled collapsed on 5/5 probed files, making the "keep only
if fails don't increase" safety guard vacuous and understating 94g's
real effect in logs. fitness.collapse_finish now forces canonical
(collapse_insearch=False) scoring for its own measurement regardless of
self's config; collapse_best now builds its evaluator canonically too
(matching what homemaker-fitness reports for the written .dom) and
threads max_share/conn_grade through. Same-family fix in
search_annealed's no-polish-budget rescore branch, which silently
defaulted to collapse_insearch=True via _evaluate's default.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uCyZJCh5mBuA2yEFxgQpo
2026-08-05 07:52:44 +01:00
30adbf4948 homemaker-py-2g7.6: NO-GO on graph-first slicing-tree construction via rectangular dualization
Research spike (DESIGN.md §37.8): classical rectangular dualization assumes
one-vertex-one-rectangle, which breaks on harbor's circulation hub (an
emergent-shape multi-leaf region, not a fixed single module) and is overkill
on the room-only adjacency graph (a trivial 3-edge matching already fully
satisfied by §11.7's seeding). No literature precedent for the multi-storey
stacking constraint either. Not prototyping; no code changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uCyZJCh5mBuA2yEFxgQpo
2026-08-05 00:25:23 +01:00
eb1248d3a5 bd: sync issues.jsonl export after 2g7.5 close
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-05 00:02:49 +01:00
ade7f9a131 homemaker-py-2g7.5: full acceptance-criteria A/B (harbor+maple, 3 seeds, 20k budget)
CP-SAT assignment does not clearly beat greedy end-to-end: worse on
harbor-house hard fails, roughly a wash on maple-court, and the reassign
operator fired in only 1 of 18 runs. Keeps assign_solver="greedy" and
enable_reassign=False as defaults; closes the bead's remaining acceptance
criterion. Raw results in experiments/results/.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-05 00:01:00 +01:00
cf634ae949 homemaker-py-2g7.5: CP-SAT exact room-code assignment (seeder + reassign op)
Adds src/homemaker_layout/cpsat.py (OR-Tools CP-SAT) as an exact alternative
to operators._assign_adjacency_aware's greedy/beam room-code placement,
wired in as assign_solver="greedy"|"cpsat" (EXPERIMENTAL, default "greedy",
byte-identical to before) through constructive_topology/lift_base_to_storeys/
driver.search, plus a new operators.mutate_reassign in-search repair
operator (driver.search's enable_reassign=False default, mirrors
enable_ruin_recreate). Both found and fixed a resize-fragility bug (a
second CP-SAT pass against settled geometry, operators._cpsat_relabel_settled)
and a CP-SAT symmetry-blowup stall (explicit interchangeable-code grouping).

Seeder-level A/B on harbor-house is a solid, low-noise positive (~13% fewer
real fitness-scored secondary-adjacency fails, 10 seeds). Full driver.search
A/B is only pilot-scale (budget=3000 vs the bead's own 20k target) and
inconclusive -- both flags stay default-off pending a larger-N confirmation.
Full writeup: DESIGN.md §37.7. Bead left in_progress (own acceptance
criteria not fully met); homemaker-py-5bv tracks the deferred post-collapse
repair item.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-04 09:19:36 +01:00
b2eded5641 bd: sync issues.jsonl export after koo close
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-03 23:33:51 +01:00
3aa08ee6ff homemaker-py-koo: multi-storey (below-link) support for the shape-curve DP
Generalise shapecurve.py's DP to process dom.levels(root) bottom-up per
storey instead of assuming a single free tree. A divided node's split is
free only per solver.free_branches' own criterion (below is None or
undivided there) -- geometry.coordinate always mirrors a below-linked
node's corners from the storey below regardless of whether that storey's
counterpart is divided, so every free region at any storey reduces to the
exact same single-region problem the pre-existing _check/realise already
solved. New _region_roots finds below-fixed leaves (checked directly,
gridless) and below-fixed-box/free-split fringe nodes per storey;
_solve_all_levels realises each storey before checking the one above and
snapshots+restores on any infeasibility, preserving solve()'s all-or-nothing
and is_feasible()'s never-writes contracts across the whole tree.
eligible() now allows any storey count.

Validated on the real (non-de-risked) examples/harbor-house: 200 random
2-storey topologies, DP-vs-NM agreement 99.5%, 0 false negatives, 117.7x
speedup (DESIGN.md §37.6). Full suite 397 passed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-03 23:30:18 +01:00
deb12bc726 bd: sync issues.jsonl export after wkh close
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-03 21:19:22 +01:00
467c732260 homemaker-py-wkh: DP-exact hard pre-filter for driver.py's shape-feasibility prune
Adds shapecurve.is_feasible() (a non-mutating refactor of solve()'s check
phase) and a shapecurve_prune flag composing the DP's exact feasible/
infeasible verdict with operators.predicted_shape_fails' existing heuristic
prune: DP-feasible vetoes a heuristic prune outright; DP-infeasible only
hard-prunes when the incumbent already has zero total fails (exact, since
infeasible proves the shape-fail floor is >=1); otherwise defers unchanged
to today's heuristic threshold. Conservative by design since a wrong prune
is unrecoverable.

Validated 0/400 false negatives across two structurally distinct plots
(harbor-house-l0 + a newly-added programme-house sweep, the first genuinely
non-rectangular plot this DP has been checked against). The real
driver.search A/B on harbor-house-l0 measured NULL (byte-identical off/on)
for a root-caused, pre-existing reason: predicted_shape_fails rarely
triggers organically at this scale, so neither new branch had an opening to
fire -- not a defect in this change. Full writeup: DESIGN.md §37.5.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-03 21:10:28 +01:00
229c3c6933 homemaker-py-6xh: wire shape-curve DP into driver.py as an NM warm-start
Promotes the validated shape-curve DP (experiments/shapecurve_spike.py,
2g7.4, DESIGN.md §37.2) from a reference-only spike into
src/homemaker_layout/shapecurve.py, and wires it into driver._evaluate as a
warm-start for innerloop.optimise: when eligible (single storey, no
leaf_sharing/superpose/max_share/multi_use) and no caller-supplied x0, the
DP's exact shape-feasible ratio point is written onto the tree before NM
runs, off by default (shapecurve_warmstart=/--shapecurve-warmstart).

Caught and fixed a latent bug promoting the spike: realise() could leave
numpy.float64 in `division`, which yaml.safe_dump can't serialise — the
original spike never round-tripped through dom.dumps so this was never hit.

A/B on harbor-house-l0 (experiments/ab_shapecurve_warmstart.py, budget=2000,
5 seeds): mean total fails 16.6 (on) vs 19.6 (off), ~3.5x mean fitness
improvement; mean hard-fail count alone was a noise-level wash at this
sample size. Full writeup in DESIGN.md §37.4.

Deliberately deferred to new tracked beads (children of 2g7): DP-exact hard
pre-filter (wkh), multi-storey below-link support (koo), leaf_sharing/
co_type modelling (tym), true skew-quad polygon algebra (ekc) — 6xh stays
in_progress pending those.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-03 18:43:28 +01:00
9296f75cdb homemaker-py-2g7.1: plan->dom composer (SVG trace -> slicing-tree .dom)
Composer half of the ground-truth bead: examples/harbor-house/drawings/
harbor-house 1.svg turned out to be a Bonsai/Blender render of 3m.dom's own
IFC (32 IfcSpace paths == 3m.dom's upper-storey leaf count), not a human
trace, so no usable reference exists yet -- this builds and tests the
pipeline that will consume one once traced. compose.py parses storey-N
Inkscape layers of cut-lines + labels against a boundary-stub .dom (plot/
height/elevation only, no room shapes to keep aligned across storeys) and
recursively detects guillotine cuts, mirroring geometry.py's own
division-line algebra; non-slicible regions and label mismatches are
reported by location rather than guessed at. homemaker-compose CLI added.
Renamed dom._link to public dom.link since compose.py needs to re-link from
outside dom.py. Full design writeup in DESIGN.md sec 37.3; actual human
tracing of harbor-house/programme-house is tracked as follow-up under
2g7.1, still open.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-03 11:03:02 +01:00
eb1d2fc7f0 bd: sync issues.jsonl export after 2g7.4 correction comment
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-03 07:21:27 +01:00
85c1183d4c homemaker-py-2g7.4: shape-curve DP prototype (Otten/Stockmeyer) — PASS
Prototype + validation for an exact size/width/proportion feasibility DP
over a frozen slicing topology, replacing the ~80-200 eval Nelder-Mead
inner loop's approximate answer to the same question with one bottom-up
pass (experiments/shapecurve_spike.py). Leaf feasible regions are exact
FAIL_THRESHOLD-inversions of fitness.py's quality_size/width/proportion;
internal-node composition runs on a shared discretised grid.

Validated on harbor-house-l0 (experiments/validate_shapecurve.py, 200
random topologies vs NM minimising shape-fail-count directly): 99.0%
agreement (0 false negatives), 93.6x speedup at grid_n=150, plot-level
bbox approximation error quantified at +7.5% (root-causing both observed
false positives). All three acceptance criteria cleared -- see DESIGN.md
§37.2 for full results and the caveats/scope not covered (multi-storey,
leaf_sharing/co_type, true skew-quad regions). Kept as a reference spike,
same status as experiments/autodiff_spike.py (§34); production wiring
into driver.py filed as homemaker-py-6xh.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-02 23:43:30 +01:00
3f2438797f bd: sync issues.jsonl export after 2g7.3 close + p6t create
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-02 19:20:08 +01:00
c644f279eb homemaker-py-2g7.3: record A/B acceptance result, close bead
DESIGN.md §37.1: hard/soft tiering A/B (harbor-house + maple-court, 3 seeds,
20k evals/run) shows hard-fail mean strictly better under the tiered
comparator on both programmes (harbor 11.67->5.33, maple 19.33->14.00) at
the cost of higher soft/total fails — the intended trade. ACCEPTANCE: PASS.

Filed homemaker-py-p6t as a non-blocking follow-up: race tiered vs flat to
0 hard fails (convergence speed) rather than composition at a fixed budget.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-02 19:00:48 +01:00
8efdc02fd9 homemaker-py-2g7.3: hard/soft fail tiering behind --use-tiers flag
Splits the flat outer-search comparator (-n_fails, fitness) into a tiered
(-n_hard, -n_soft, fitness) so search budget stops being spent polishing
SOFT shape fails (crinkliness/proportion/size/width/edge-too-long/
staircase-volume) while HARD structural fails (missing space, wrong/
required level, level/circulation/vertical connectivity, adjacency,
stairs, covered-outside, storey limits, public access) remain unfixed.

fitness.classify_fail_tier/tier_counts classify every fail string emitted
across fitness.py and graph.py, raising on anything unrecognised so new
fail sites must declare a tier. Validated against all real fail strings in
the checked-in corpus plus every fail-emission call site read from source.

driver.Individual gains n_hard/n_soft (populated from innerloop.Result.
fail_lines); search(use_tiers=...) swaps the comparator when set (default
off, so existing runs are unaffected — inner-loop 0.5^n cliff untouched).
evolve.py exposes --use-tiers / HOMEMAKER_USE_TIERS.

experiments/tier_ab_2g7_3.py runs the acceptance A/B (harbor+maple, 3
seeds, 20k evals) in the background; results pending.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSwQwpEaHFBkeVSDDWd75S
2026-08-02 16:00:39 +01:00
91ff4fdcaa bd: close homemaker-py-cvw
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dq3WAXft8RszMG2CLH7VkU
2026-08-02 10:54:54 +01:00
2f26f4658b homemaker-py-cvw: clear geometry cache at substrate_readiness and collapse_global entry
Fixes the stale id()-keyed geometry cache read in parallel staged runs:
substrate_readiness runs in the parent process every tournament/admit
comparison but the parent's score_with_fails (which normally clears
geometry._cache) only runs in pool workers when n_workers>1, so evicted
trees' freed addresses can alias into freshly unpickled ones. Also adds
a defensive clear at collapse_global entry per the bead's recommendation
for the same cache class of hazard.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dq3WAXft8RszMG2CLH7VkU
2026-08-02 10:52:40 +01:00
507403c9b2 bd: sync issues.jsonl export after r5a close + d86 note
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dq3WAXft8RszMG2CLH7VkU
2026-08-02 10:46:36 +01:00
12247248d5 homemaker-py-r5a: canonicalise stale leaf-share stamps before any relabel
collapse_global's own commit could relabel a leaf back to the code its
stale share_type names, making share_type == type true again and
resurrecting a multiplicity credit for area never sized for it -- the
commit-door companion to the iio valuation bug. dom.canonicalize_shares()
drops share/share_type whenever share_type != type; called at the top of
collapse_global (covers collapse_global's own commit, 2-opt, and standalone
finish-time use) and _evaluate_full (covers collapse_superposition and
ordinary retype mutations) so the guard is an actual invariant instead of
a per-reader check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dq3WAXft8RszMG2CLH7VkU
2026-08-02 10:45:12 +01:00
522f9b1d68 homemaker-py-2g7: file Phase 9 epic — ground truth, exact evaluation, solver-directed search (DESIGN.md §37)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjyStTdLWFMtdScrpbgQur
2026-08-02 10:16:56 +01:00
7257fce7ca homemaker-py-zrx: expert review of numeric/scoring path — 3 confirmed bugs filed (DESIGN.md §36)
Review of fitness.py/solver.py/collapse_cmd.py/innerloop.py/driver.py for
silent score-corrupting bugs (the iio class). Filed with verified repros:
r5a (stale-share resurrection via collapse commit), cvw (parallel staged
stale id()-keyed geometry cache), sd3 (collapse_best keep-better guard
vacuous under baked-in collapse_insearch), pek (shadowed process_storey).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjyStTdLWFMtdScrpbgQur
2026-08-02 09:21:58 +01:00
437241ae25 bd: file homemaker-py-zrx, expert review of scoring/collapse path
Scoped review request for a stronger model to audit fitness.py,
solver.py, collapse_cmd.py, and the collapse_insearch path for
silent numeric bugs analogous to the iio stale-share leak.
2026-08-02 08:47:31 +01:00
6822e5dbb3 bd: sync issues.jsonl export after iio notes + d86 filed
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8agJBT2ZpmF3ErW7wi2wY
2026-08-02 07:57:48 +01:00
3069217c29 homemaker-py-iio: document retroactive impact of stale-share collapse bug (DESIGN.md §35)
Adds a full writeup of the root cause (already fixed in 929be5b) plus a
same-codebase fix-vs-no-fix re-verification: harbor-house qpk-protocol
seeds 1-3 show collapse_insearch=OFF unaffected, but ON diverges by 5-8
fails on 2/3 seeds, non-directionally. Confirms the bug was not merely
theoretical for historical leaf_sharing+collapse_insearch runs, though the
noise is unlikely to have flipped 1ph's aggregate N=20 verdict. Adds a
caveat postscript to §20 (qpk) and files homemaker-py-d86 for the rigorous
historical-commit re-verification this session didn't do.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8agJBT2ZpmF3ErW7wi2wY
2026-08-02 07:56:33 +01:00
838cef5930 bd: sync issues.jsonl export after iio close
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8agJBT2ZpmF3ErW7wi2wY
2026-08-01 21:13:09 +01:00
929be5b144 homemaker-py-iio: fix stale leaf-share leak in collapse_global's probe valuation
_collapse_value and _usage_quality temporarily overwrite leaf.type to probe a
hypothetical candidate code, but graph.leaf_share reads that overwritten type
against leaf.share_type -- so a stale share (left over from a code the leaf
was since retyped away from) spuriously reactivates whenever the probed
candidate happens to equal the old share_type, skewing the Hungarian
assignment's cell value for that (leaf, code) pair. dom.dump/dom.load drops
such stale metadata on reload (dom._emit only serialises share when
share_type==type), so a live search tree carrying it and its dump/reload
round trip fed different values into the same collapse_global call and
landed on different optimal matchings.

Fix: neutralise share_type during the probe whenever the candidate differs
from the leaf's real current type, restoring it in the finally block. The
leaf's own current type still legitimately carries a live share.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8agJBT2ZpmF3ErW7wi2wY
2026-08-01 21:08:32 +01:00
b0bd1a896b homemaker-py-91f: residual diagnostic on the current full default stack
Re-ran the §13.1/§13.2-style per-leaf fail-breakdown diagnostic on real
driver.search_staged runs (budget 20000, seeds 0-2, harbor-house and
maple-court) under the current full default stack (leaf-sharing x3,
depth-balanced, interior-O, share-aware edge cap) -- never decomposed by
category since those defaults were flipped on.

Finding: crinkliness (48%) and size (20.6%) now dominate the residual on
both programmes (~69% combined); construction-completeness fails
(missing space, adjacency, level, connectivity) are down to a small
tail (<=6% each). This revises erc.1's old recommendation to deprioritise
compactness-cuts in favour of leaf-sharing -- leaf-sharing is now fully
deployed and crinkliness is proportionally more dominant than ever, so
DESIGN.md §13.11 recommends reopening a compactness/crinkliness-targeted
construction lever as the next concrete step.

Also files two bugs found while validating the methodology: dumping and
reloading a .dom under leaf_sharing+collapse_insearch does not reproduce
the search's own in-process fail count (homemaker-py-iio), and
run_staged_search.py's own sanity rescore omits the collapse_insearch
override (homemaker-py-7ua). experiments/run_and_capture_91f.py sidesteps
this by capturing the true in-process fails list instead of rescoring
from disk; experiments/diag_residual_91f.py tallies fail categories from
those sidecars.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8agJBT2ZpmF3ErW7wi2wY
2026-08-01 19:38:46 +01:00
e377cec145 bd: sync issues.jsonl export after filing 4 next-step issues
Filed from a DESIGN.md/memory review: residual diagnostic on the
current full construction stack (91f), 2-opt polish inside
collapse_insearch (fe2), health-centre stack validation (7xb), and
the parallel/BLAS non-determinism noise source flagged in §14 (b8g).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8agJBT2ZpmF3ErW7wi2wY
2026-08-01 11:08:33 +01:00
da6b4c2143 bd: sync issues.jsonl export after 2ax close
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8agJBT2ZpmF3ErW7wi2wY
2026-08-01 10:31:26 +01:00