Repository navigation
gen_bittings and check_bittings follow and note the key shape rules (D64, step 3) - #37
Conversation
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
left a comment
There was a problem hiding this comment.
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.pysaysscanner=false): 998 passed, 16 skipped.check_no_stray_data.py --historyis 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-Bytrailer. 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.unmeetableproduces 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
mainand the head (rules turned off) on a pattern run and on an--avoid/--min-diff 4run. Stdout, stderr and exit codes are identical. - Probes:
check_bittingsprintsSHAPElines with pin positions only, never cuts. They do not change the exit status. The last line is stillOKor the problem count.--masternaming an unknown key is a usage error.--max-run -1,0,OFFandnonebehave as the tests say.--pins 1,2and4generate.--masterwith 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.mdhave 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
…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
left a comment
There was a problem hiding this comment.
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.FLAGSnow covers all five rules, andgive_up_messageuses it../gen_bittings.py --pins 7 -n 3 --masterstill 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. unmeetableaccepts 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 --masternow 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. Leavingunmeetablesimple 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.
drawsisattempts - 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-variationand "100% of the draws", which is right. - The commit is authored and committed as the noreply address, with the
Co-Authored-Bytrailer. 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
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.
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 passunchanged and its messages are the same.
gen_bittingsonly prints bittings that follow the rules: by default no equal adjacentcuts, no depth more than three times, no monotone key, and with
--mastera span of atleast six.
--max-run,--max-same-depth,--min-variation,--master-min-spanand--allow-monotonechange them; each takes a number oroff.--master-min-spanis notin 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_bittingstakes the same flags, and--master NAME(repeatable) for the keys thespan rule applies to. It prints an advisory
SHAPEline per broken rule, with pinpositions and never the cuts. They are not counted as problems and do not change the exit
status, as the design says.
shape_args.py, listed indocs/design.md. A rule no key could meet is a usage error (exit 2) that names the flag.defaults and the flags.
The solver and
check_systemdo not use the rules yet (steps 4 and 5), and the README says so.Route: a pull request, because
maintakes 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
pytestpasses. A bug fix has a regression test.docs/decisions.mdand, if it changes how things are, an edit todocs/design.md(and the feature's document indocs/designs/, if it has one). The decision is D64; the design document anddesign.mdhave the edits.secrets,random.SystemRandom) unchanged.Behavior changes and AI assistance
gen_bittingsnow filters its output, so its default output changes: it no longer prints akey with equal neighbours, a depth four times, a one-way key, and, with
--master, a narrowone. 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 newcode with the same seeded draws on four argument sets (a pattern, no pattern,
--avoidwith--min-diff, and 5 pins with--max-step 3) and compared.check_bittingsprints newSHAPElines and a count line; its exit status and its last line (OKor the problem count)are as before. The solver's scoring and algorithms are untouched (D6).
Tests run:
ci_changes.pysaysscanner=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