Skip to content

doe-designer Claude Skill + minimum moment aberration - #485

Merged
kgdunn merged 8 commits into
mainfrom
claude/factorial-distribution-redesign-37sz7m
Aug 10, 2026
Merged

doe-designer Claude Skill + minimum moment aberration#485
kgdunn merged 8 commits into
mainfrom
claude/factorial-distribution-redesign-37sz7m

Conversation

@kgdunn

@kgdunn kgdunn commented Aug 7, 2026

Copy link
Copy Markdown
Owner

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_spec DOE tools with the workflow knowledge an LLM does not reliably have on its own.
  • .claude-plugin/marketplace.json - /plugin marketplace add kgdunn/process-improve works, and the skill can also be dropped into ~/.claude/skills/ or zipped for claude.ai.
  • Minimum moment aberration (Xu, 2003) - a new moment_aberration public function and evaluate_design metric.

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.md leads 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_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. Worth noting how wide that gap is in practice: 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 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)/2 and expanding the u-th moment of h as a sum of squares over column tuples, minimised at n^2 E_u(m) where E_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 as Fractions, 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_spec registry, 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-resolution to fail outright (exit 3), and --compare to rank candidates by minimum moment aberration.
  • render_plot.py - turns a visualize_doe chart 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_aberration reproduces 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 IV
  • Reproduces the published patterns for the 8-, 16- and 32-run minimum aberration designs (Tables 3, 5, 7, 9, 11)
  • Moment-derived resolution agrees with the shortest word in the defining relation across eight regular designs
  • Catches the failure modes it exists for: duplicated column (res II), unbalanced column (res I), and a non-regular design the word-length route cannot evaluate at all
  • E_u(m) closed form brute-force-checked against direct enumeration
  • 55 new tests; full suite 2223 passed, 4 skipped
  • ruff check . and mypy src/process_improve clean
  • All three skill scripts run end to end (design -> verify -> analyse -> plot), including the non-zero exit path on a failing design

Checklist

  • Version bumped in pyproject.toml (1.62.2 -> 1.63.0, MINOR: new public API and a new distribution channel; CITATION.cff kept in sync)
  • Tests added or updated where relevant
  • ruff check . passes
  • CHANGELOG.md updated

Note

uv.lock is deliberately not committed, per CLAUDE.md.

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
@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.32710% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/process_improve/experiments/evaluate.py 78.57% 3 Missing ⚠️
.../process_improve/experiments/_moment_aberration.py 97.82% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

claude added 6 commits August 7, 2026 22:48
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
kgdunn merged commit 3b1a1e9 into main Aug 10, 2026
14 checks passed
@kgdunn
kgdunn deleted the claude/factorial-distribution-redesign-37sz7m branch August 10, 2026 05:13
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
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.

2 participants