Context
Came out of the #467 review (#467 (comment)). Two related cleanups were deferred as a wider refactor:
1. Unify required-file discovery across init / generate / execute
Each surface that validates a project folder does its own discovery and its own "missing X" message:
optics init scaffolds a fixed file set.
optics generate (helper/generate.py around required = {...}) checks for config.yaml, a test-cases file, a modules file, and an elements file, then raises a bespoke ValueError.
optics execute / optics dry_run (helper/execute.py find_files / _load_*) routes files into buckets and fails with E0501 when a required bucket is empty.
Three call sites, three error shapes, three sets of "what's actually required" logic. A project that's valid for execute can still be rejected by generate (or vice versa) for reasons that surprise the user. Consolidate into one discovery + validation path so the required-set is defined once and the messages are consistent.
2. Make elements optional in optics generate
generate.py currently treats the elements file as required. An API-only project (one that uses the Invoke Api keyword and ships api.yaml instead of elements.csv) has no elements file and is valid at execute time, but optics generate rejects it. Drop elements from the required set in generate — a project should be generatable as long as it has config.yaml + test cases + modules.
Out of scope for #467
Not folded into the onboarding PR since it touches three surfaces and changes error contracts; better as its own change with its own tests.
Context
Came out of the #467 review (#467 (comment)). Two related cleanups were deferred as a wider refactor:
1. Unify required-file discovery across init / generate / execute
Each surface that validates a project folder does its own discovery and its own "missing X" message:
optics initscaffolds a fixed file set.optics generate(helper/generate.pyaroundrequired = {...}) checks forconfig.yaml, a test-cases file, a modules file, and an elements file, then raises a bespokeValueError.optics execute/optics dry_run(helper/execute.pyfind_files/_load_*) routes files into buckets and fails withE0501when a required bucket is empty.Three call sites, three error shapes, three sets of "what's actually required" logic. A project that's valid for
executecan still be rejected bygenerate(or vice versa) for reasons that surprise the user. Consolidate into one discovery + validation path so the required-set is defined once and the messages are consistent.2. Make
elementsoptional inoptics generategenerate.pycurrently treats the elements file as required. An API-only project (one that uses the Invoke Api keyword and shipsapi.yamlinstead ofelements.csv) has no elements file and is valid at execute time, butoptics generaterejects it. Drop elements from the required set ingenerate— a project should be generatable as long as it hasconfig.yaml+ test cases + modules.Out of scope for #467
Not folded into the onboarding PR since it touches three surfaces and changes error contracts; better as its own change with its own tests.