doe-designer Claude Skill + minimum moment aberration - #485
Merged
Conversation
Adds a Claude Skill / plugin distribution channel for the designed-experiments tooling, and implements minimum moment aberration (Xu, 2003) so any two-level design can be verified without a defining relation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A76tHBdyviKJ4RtwiiGFzm
9 tasks
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Implements Xu (2003) minimum moment aberration, exported as process_improve.experiments.moment_aberration. The existing minimum_aberration metric reads the word-length pattern off the defining relation, so it needs a DesignResult carrying generators. Handed a bare matrix it has nothing to work from, which rules out the case that matters most: checking a design this library did not construct. Moment aberration is computed from the pairwise similarities between runs, so it needs only the matrix. It is equivalent to minimum aberration for regular designs, extends to non-regular ones, and costs O(n^2 m^2) rather than O(n 2^m). Comparing each moment against its attainable lower bound yields the design strength, and hence a resolution, for any two-level matrix. The lower bound is derived by writing delta = (m + h)/2 and expanding the u-th moment of h as a sum of squares over column tuples, which is minimised at n^2 E_u(m) with E_u(m) the number of tuples whose columns all appear an even number of times. Every power sum is formed in exact Python integers via a similarity histogram, and compared as Fractions, so strength detection is exact rather than tolerance-based. Verified against the worked 2^(7-3) example in Vazquez et al. (2026): pattern (3.27, 11.67, 42.47, 157.27, 591.27, 2251.67, 8666.47), resolution 4. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A76tHBdyviKJ4RtwiiGFzm
…erns 49 tests. The reference values are the moment aberration patterns published in Vazquez et al. (2026) for the 8-, 16- and 32-run minimum aberration designs, plus the fully-printed 2^(7-3) design in their Table 1. Also cross-checks the moment-derived resolution against the shortest word in the defining relation for eight regular designs, covers the failure modes the criterion exists to catch (duplicated column, unbalanced column, a non-regular design that the word-length-pattern route cannot evaluate at all), and brute-force-enumerates E_u(m) against its closed form. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A76tHBdyviKJ4RtwiiGFzm
Registers the metric and cross-checks it against a design's declared resolution. Disagreement is surfaced explicitly: a matrix that no longer matches the design it claims to be is precisely what this metric is for. Worth noting how wide the gap is. generate_design does not populate DesignResult.generators for fractional factorials, so minimum_aberration returns 'Not a fractional factorial design' even for designs this library generated itself. moment_aberration reads the matrix, so it answers in both cases. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A76tHBdyviKJ4RtwiiGFzm
Three CLI entry points for the Claude Skill bundle: - doe_tool.py: generic dispatcher over the whole @tool_spec registry, JSON in and JSON out. Generic on purpose, so it cannot go stale as tools are added. - verify_design.py: the gate. Reads a two-level design CSV and reports the resolution the matrix actually has, not the one it is labelled with, with --require-resolution to fail the check outright. Also ranks candidate designs by minimum moment aberration. - render_plot.py: turns a visualize_doe chart spec into a PNG/SVG/PDF via kaleido, or a self-contained interactive HTML page that needs nothing installed to view. Adds a skills/** per-file-ignores block: these are user-facing CLI scripts, so print() is the output channel and process_improve is imported lazily to turn a missing optional extra into an install hint rather than a traceback. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A76tHBdyviKJ4RtwiiGFzm
SKILL.md leads with the rule that matters: never write out a design matrix, generate it and then verify it. References cover choosing a design, verifying one, the analysis sequence, and a full worked example. The worked example is a real run, not an illustration. Screening 7 factors in a 16-run resolution IV design recovers the two active factors, and the three aliased two-factor interactions come back with identical estimates of 1.773, which makes what resolution IV costs visible rather than abstract. Adds .claude-plugin/marketplace.json so the skill installs with /plugin marketplace add kgdunn/process-improve. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A76tHBdyviKJ4RtwiiGFzm
MINOR: new public API (moment_aberration), a new evaluate_design metric, and a new distribution channel. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A76tHBdyviKJ4RtwiiGFzm
kgdunn
pushed a commit
to kgdunn/factorial
that referenced
this pull request
Aug 7, 2026
Custody of a user's Anthropic API key is a real security burden: an AES-256-GCM token ciphertext, an Argon2-derived KEK, a wrapped DEK, a per-session re-wrap, orphaning on password reset, re-wrapping on password change, a master key whose loss silently breaks every active session, and an append-only audit table. That is a lot of surface to carry for a feature with no users. The doe-designer Claude Skill (kgdunn/process-improve#485) covers the same need better: a user who wants to spend their own Anthropic quota runs the tooling in their own Claude account, and nobody else ever holds the key. Removed across backend, frontend, schema and docs. The argon2-cffi, cryptography and maxminddb dependencies go with it; maxminddb was the GeoIP driver, missed in the previous commit. Schema: migration 0012 drops six columns from users, two from sessions, messages.byok_used, and the byok_credentials_history table. This is contract-destructive and NOT blue-green safe; the migration docstring says so and explains what the two-deploy version would have looked like. Deploy it with both colours down. Backend 330 passed, 2 skipped. Frontend: 427 files, 0 errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A76tHBdyviKJ4RtwiiGFzm
The branch was cut from 0e8e8d1 on 7 August, before #486 through #490 merged, and had gone stale. Four files conflicted. Version metadata. This branch set 1.63.0 in pyproject.toml and CITATION.cff, but 1.63.0 was released from main on 8 August by #486, and main now stands at 1.66.1. Taking this branch's value would have moved the version backwards onto a number already in use, so main's 1.66.1 is kept in both files and no bump is made here. CHANGELOG. The "## [1.63.0] - 2026-08-07" heading is dropped for the same reason and its body moves under [Unreleased], leaving main's released history untouched. The link-reference footer is taken from main, which carries the four releases this branch predates. experiments/__init__.py. Both sides appended to __all__ in the same region: this branch added moment_aberration, main added manufacture and omars_minimum_runs. All three are kept, alphabetical order restored, and the list checked programmatically against the module's imports. evaluate.py merged without conflict. One thing the merge could not flag. SKILL.md stated that ten @tool_spec DOE tools are reachable through the dispatcher and listed them in a table. Main added an eleventh, trade_off_table, in #487. The count and the table are corrected, and the documented list is now checked against the modules actually present in experiments/_tools. Verification after the merge: ruff check . and ruff format --check . clean mypy src/process_improve clean, 146 source files pytest: 2530 passed, 5 skipped, coverage 94.12% moment_aberration still reproduces the paper's Table 1 pattern exactly (3.27, 11.67, 42.47, 157.27, 591.27, 2251.67, 8666.47) at resolution IV, both directly and through the evaluate_design metric all three skill scripts run, including the non-zero exit path: verify_design.py --require-resolution 5 exits 3 on a resolution IV design Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1daHPaXLs7PPRsq8CmMMm
kgdunn
added a commit
that referenced
this pull request
Aug 10, 2026
#485 landed the doe-designer skill and minimum moment aberration. Merging it in exposes call sites that this branch's renames break, none of which git flags. CHANGELOG was the only textual conflict: both sides had added to [Unreleased]. Entries from both are kept, main's first in each subsection. Three schema-key call sites in the skill. The n_ prefix sweep renamed generate_design's `center_points` and `replicates` inputs, and the skill passes those keys as live JSON: examples/design_spec.json "center_points": 0, invoked by SKILL.md, examples/README.md and worked-example.md references/worked-example.md:59 the prose describing that call references/worked-example.md:199 a runnable CCD command Left alone, the skill's flagship example would fail input validation rather than degrade. All three now use n_center_points, and all three documented commands were run to confirm it. The English words are untouched: "center points or replicates", "extra replicates", "3 replicates at the optimum". Only keys in payloads changed. Three tests in test_moment_aberration.py called generate_design with center_points=; updated to n_center_points=. Also corrected, unrelated to the rename: the CHANGELOG entry for the skill said it exposes "the ten designed-experiments tools". trade_off_table (#487) made it eleven, which SKILL.md already reflected after the #485 merge. Citation narrowed in three places. SKILL.md, references/verification.md and scripts/verify_design.py each stated that the Vazquez, Rother and Charles-Gonzalez study (arXiv:2512.17113) ran GPT-5.1 and Gemini 2.5 Flash over 36 tasks with ten replicates, and that the failures were resolution 1 or 2, non-regular arrays offered as regular fractions, and tables with missing cells. The paper's abstract supports the run sizes, the factor range, the GPT and Gemini families, and reliability up to about eight factors; it does not name model versions, task or replicate counts, or those specific failure modes. The text now claims only what is verifiable, and the authors are named in full. Verification after the merge: ruff check . and ruff format --check . clean mypy src/process_improve clean, 146 source files pytest: 2538 passed, 5 skipped API naming scan over the merged code: no scalar count missing the n_ prefix, including everything #485 added all 44 numeric checks behind the pid-book sections still pass MCP surface as intended: trade_off_table still keyed on runs and factors, generate_design now on n_center_points and n_replicates skill scripts run end to end, including verify_design.py --require-resolution 5 exiting 3, and the CCD command from worked-example.md Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1daHPaXLs7PPRsq8CmMMm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Opens a second distribution channel for the designed-experiments tooling: a Claude Skill (plus a plugin marketplace catalog) that users install into their own Claude account, alongside the existing hosted web app. The library is the computation; the skill carries the methodology.
skills/doe-designer/- a Claude Skill wrapping the ten@tool_specDOE tools with the workflow knowledge an LLM does not reliably have on its own..claude-plugin/marketplace.json-/plugin marketplace add kgdunn/process-improveworks, and the skill can also be dropped into~/.claude/skills/or zipped for claude.ai.moment_aberrationpublic function andevaluate_designmetric.Why now
Vazquez, Rother and Charles-Gonzalez (arXiv:2512.17113v2, March 2026) evaluated GPT-5.1 and Gemini 2.5 Flash on 36 two-level fractional factorial construction tasks (8/16/32 runs, 4 to 26 factors, 10 replicates each). The models produce optimal designs reliably up to about eight factors and then degrade, and the degradation is the dangerous kind: compliant-looking tables that are actually resolution 1 or 2, non-regular arrays presented as regular fractions, and tables with missing cells.
That is the argument for the skill existing. An LLM asked to do DOE should be routed to a catalogue-backed generator and a verifier, not left to emit a design matrix token by token.
SKILL.mdleads with exactly that rule, and the new metric is what lets the verifier check a matrix it did not generate.Minimum moment aberration
The existing
minimum_aberrationmetric reads the word-length pattern off the defining relation, so it needs aDesignResultcarryinggenerators. Handed a bare matrix it has nothing to work from, which rules out the case that matters most. Worth noting how wide that gap is in practice:generate_designdoes not populateDesignResult.generatorsfor fractional factorials, sominimum_aberrationreturns "Not a fractional factorial design" even for designs this library generated itself.Moment aberration is computed from the pairwise similarities between runs, so it needs only the matrix. It is equivalent to minimum aberration for regular designs, extends to non-regular ones, costs O(n^2 m^2) rather than O(n 2^m), and yields the design's strength and hence a resolution for any two-level matrix.
The lower bound is derived by writing
delta = (m + h)/2and expanding the u-th moment ofhas a sum of squares over column tuples, minimised atn^2 E_u(m)whereE_u(m)counts tuples whose columns all appear an even number of times. Every power sum is formed in exact Python integers via a similarity histogram and compared asFractions, so strength detection is exact rather than tolerance-based. Bounds are reported only up to the first order the design misses; past that the bound is valid but so slack it can go negative, and reporting it would invite a meaningless comparison.The skill
Three CLI entry points, all lint-clean and exercised end to end:
doe_tool.py- generic dispatcher over the whole@tool_specregistry, JSON in and JSON out. Generic on purpose, so it cannot go stale as tools are added.verify_design.py- the gate. Reports the resolution a matrix actually has, with--require-resolutionto fail outright (exit 3), and--compareto rank candidates by minimum moment aberration.render_plot.py- turns avisualize_doechart spec into PNG/SVG/PDF via kaleido, or a self-contained interactive HTML page that needs nothing installed to view.Plus four references (choosing a design, verification, analysis workflow, worked example) and runnable examples.
The worked example is a real run, not an illustration. Screening 7 factors in a 16-run resolution IV design recovers the two active factors, and the three aliased two-factor interactions come back with identical estimates of 1.773 - which makes what resolution IV costs visible rather than abstract, and shows up on the half-normal plot as a single point wearing three labels.
Test plan
moment_aberrationreproduces the published pattern for the 2^(7-3) design printed in full in the paper's Table 1:(3.27, 11.67, 42.47, 157.27, 591.27, 2251.67, 8666.47), resolution IVE_u(m)closed form brute-force-checked against direct enumerationruff check .andmypy src/process_improvecleanChecklist
pyproject.toml(1.62.2 -> 1.63.0, MINOR: new public API and a new distribution channel;CITATION.cffkept in sync)ruff check .passesCHANGELOG.mdupdatedNote
uv.lockis deliberately not committed, perCLAUDE.md.