Skip to content

gen_bittings and check_bittings follow and note the key shape rules (D64, step 3) - #37

Merged
twilde merged 3 commits into
mainfrom
shape-rules-cli
Oct 6, 2026
Merged

twilde merged 3 commits into
mainfrom
shape-rules-cli

Conversation

@twilde

@twilde twilde commented Oct 6, 2026

Copy link
Copy Markdown
Owner

What and why

Step 3 of the key shape rules design (D64): the generator
and the quick checker use the rules. Two commits, each readable on its own.

  1. Refactor, no behavior change. The checks for a rule no key could meet (a master span or
    a total variation above what the key space allows) move from the config into
    ShapeRules.unmeetable(space), so the command line can use them. The config's tests pass
    unchanged and its messages are the same.
  2. The tools.
    • gen_bittings only prints bittings that follow the rules: by default no equal adjacent
      cuts, no depth more than three times, no monotone key, and with --master a span of at
      least six. --max-run, --max-same-depth, --min-variation, --master-min-span and
      --allow-monotone change them; each takes a number or off. --master-min-span is not
      in the design's list of flags and is added to it (otherwise a master's span could not be
      changed). When the search gives up, the message says which rules turned draws down; no
      rule is ever relaxed on its own.
    • check_bittings takes the same flags, and --master NAME (repeatable) for the keys the
      span rule applies to. It prints an advisory SHAPE line per broken rule, with pin
      positions and never the cuts. They are not counted as problems and do not change the exit
      status, as the design says.
    • The flags and their checks are in a new shared module, shape_args.py, listed in
      docs/design.md. A rule no key could meet is a usage error (exit 2) that names the flag.
    • The README has a "Key shape rules" section, and tests keep its table in step with the
      defaults and the flags.

The solver and check_system do not use the rules yet (steps 4 and 5), and the README says so.

Route: a pull request, because main takes changes by pull request and the code should pass CI.

Never include real key data

None: the tests and README use invented keys (checked by hand against MACS, closeness and the
rules they are meant to show).

Checklist

  • I have not included real bittings, real system files, or anything that identifies a real building.
  • One logical change (refactors are in their own commits).
  • Tests added or updated, and pytest passes. A bug fix has a regression test.
  • README updated if behavior changed; a design decision gets a short entry in docs/decisions.md and, if it changes how things are, an edit to docs/design.md (and the feature's document in docs/designs/, if it has one). The decision is D64; the design document and design.md have the edits.
  • No new runtime dependencies; randomness defaults (secrets, random.SystemRandom) unchanged.

Behavior changes and AI assistance

gen_bittings now filters its output, so its default output changes: it no longer prints a
key with equal neighbours, a depth four times, a one-way key, and, with --master, a narrow
one. With every rule turned off (--max-run off --max-same-depth off --allow-monotone --master-min-span off) the output is byte-for-byte what it was: I ran the old and new
code with the same seeded draws on four argument sets (a pattern, no pattern, --avoid with
--min-diff, and 5 pins with --max-step 3) and compared. check_bittings prints new
SHAPE lines and a count line; its exit status and its last line (OK or the problem count)
are as before. The solver's scoring and algorithms are untouched (D6).

Tests run: ci_changes.py says scanner=false, so the whole suite in a venv with only
.[test]: 998 passed, 16 skipped.

Written with Claude Code (Co-Authored-By trailer on the commits).

🤖 Generated with Claude Code

twilde and others added 2 commits October 6, 2026 15:50
The config's checks for a master span or total variation no key could meet
become a method of ShapeRules, so the generator and checker can use them for
their command-line rules. No behavior change: the config's tests pass
unchanged and its messages are the same.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…tep 3)

gen_bittings only prints bittings that follow the shape rules (by default no
equal adjacent cuts, no depth used more than three times, no monotone key,
and with --master a span of at least six), with --max-run, --max-same-depth,
--min-variation, --master-min-span and --allow-monotone to change them; a
number or "off" sets each. When the search gives up, the message says which
rules turned draws down. check_bittings takes the same flags and --master
NAME, and prints an advisory SHAPE line, positions only, for each rule a key
breaks; it does not count as a problem or change the exit status. The flags
live in a new shared module, shape_args.py, which also refuses a rule no key
of the key space could meet.

README gets a "Key shape rules" section, kept in step with the code by tests,
and the design gets the two small additions (--master-min-span, "off").

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@twilde twilde left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Nothing blocks; two Optional notes below.

Reviewed head 217736b. What I ran, in a scratch worktree:

  • Merged the head into current main (63a6d94). It was already up to date, so there was no merge to test. Whole suite in a venv with only .[test] (ci_changes.py says scanner=false): 998 passed, 16 skipped. check_no_stray_data.py --history is clean.
  • CI on the head is green (all test jobs, the stray-data check, CodeQL; the scanner job is skipped, as expected).
  • Both commits are authored and committed as the noreply address and carry a Co-Authored-By trailer. I found no seven-digit strings that are not invented, and no key-history facts in the diff or the messages. The README, design and test keys are fake.
  • The refactor claim: ShapeRules.unmeetable produces the same two messages as the old config code, and the config tests pass unchanged.
  • The "byte-for-byte with every rule off" claim: with seeded draws, I compared main and the head (rules turned off) on a pattern run and on an --avoid / --min-diff 4 run. Stdout, stderr and exit codes are identical.
  • Probes: check_bittings prints SHAPE lines with pin positions only, never cuts. They do not change the exit status. The last line is still OK or the problem count. --master naming an unknown key is a usage error. --max-run -1, 0, OFF and none behave as the tests say. --pins 1, 2 and 4 generate. --master with 5 pins generates.
  • Docs: the README table is kept in step with the defaults and flags by the new tests. D64 already covers the design, and the design document and design.md have the matching edits.

Two Optional notes inline: the give-up message uses rule field names where the user needs flag names, and a --pins 3 --master search that cannot succeed runs to the attempt limit.

Review written with AI assistance (Claude).


Generated by Claude Code

Comment thread sfic_solver/gen_bittings.py Outdated
Comment thread sfic_solver/model.py
…e took most draws

Review feedback on #37: the message named rules by field name where the user's
handle is the flag, and a combination of rules that no key can meet (three
pins with --master) ran to the attempt limit with only a tally. The message
now names the flag that governs each rule, and says so when one rule turned
down at least 80% of the draws. The design records that the reachability
bounds look at each rule alone.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@twilde twilde left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Both earlier threads are closed, and the new commit is clean. Nothing blocks and I have no new notes.

Re-review at head f814c6e (one new commit on top of the head I reviewed, 217736b).

Earlier threads:

  • Give-up message names field names (Optional, gen_bittings.py): closed. shape_args.FLAGS now covers all five rules, and give_up_message uses it. ./gen_bittings.py --pins 7 -n 3 --master still works, and the failing 3-pin case now reads "by the flag that governs it: --master-min-span 87,968, --allow-monotone 53,032, --max-run 22,819". The new tests check that every rule has a flag, and that no field name appears in the message.
  • unmeetable accepts a combination no key can meet (Optional, model.py): closed. I asked for either a message hint or a design sentence, and you did both. --pins 3 --master now ends with "--master-min-span turned down 88% of the draws, so it may not be possible with the other rules", and "What cannot be known yet" in the design records that the bounds look at each rule alone. A test pins the 3-pin case. Leaving unmeetable simple is fine.

New commit:

  • The 80% rule only fires on a hedged "may not be possible" sentence and does not change what the tool does. draws is attempts - 1, which is the number of draws actually made when the limit is hit. I also ran --pins 4 -n 20 --min-diff 0 --min-variation 15, and it names --min-variation and "100% of the draws", which is right.
  • The commit is authored and committed as the noreply address, with the Co-Authored-By trailer. The message and the design sentence contain no real key data and no building facts.

What I ran, in a scratch worktree: main (63a6d94) is an ancestor of the head, so there is nothing to merge. The whole suite in a venv with only .[test] (ci_changes.py says scanner=false): 1002 passed, 16 skipped, up from 998 with the four new tests. check_no_stray_data.py --history is clean. CI on f814c6e is green (all test jobs, the stray-data check, CodeQL; the scanner job is skipped, as expected). The earlier main versus head comparison with the rules off still holds, since the new commit only touches the give-up path.

Review written with AI assistance (Claude).


Generated by Claude Code

@twilde
twilde merged commit cadca36 into main Oct 6, 2026
12 checks passed
@twilde
twilde deleted the shape-rules-cli branch October 6, 2026 21:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant