Add an engine through the registry
latin_rectangle() is the worked example: its engine,
declaration and tests were added after the generic registry
infrastructure, without adding a branch to replay, schema, printing,
layout or drawing dispatchers.
- Write independent scientific tests first. Specify counts and labels from the requested inputs, not from the result’s own summary. Check geometry, replications, model rank/efficiency where relevant, and corrupted fixtures. State the construction family, sampling limitations and a finite search budget. A fixed-seed snapshot alone is not scientific validation.
- Add an exported
R/fct_<engine>.Rfunction. Validate types, counts, products, labels and options before allocating large data or callingresolve_seed(). Calllocal_design_seed()once the effective seed is known. Do not detach packages, print status, change options or call Shiny. Use classed conditions. - Return through
new_fieldhub_design(), withinfoDesign$id_designand its effective seed, common field-book keys and a complete named parameter list. Include choices that change output and supplied data needed for replay. - Add one declaration in
R/result_design_registry.R: stable snake-case key, public engine name, required columns (or a pure column-resolver function), and optional title/layout/render handlers. A fixed-coordinate book with aTREATMENTcolumn can usefield_book_layoutsanddraw_registered_layout. Declare specialized handlers only if the generic contract does not fit. Never add metadata-directedeval()or dispatch to arbitrary saved names. - Regenerate Rd/NAMESPACE with
devtools::document(). Add fixed-seed calls totests/testthat/helper-catalogue.Rand the result-class expectations. Test explicit/automatic seeds, errors without RNG leakage, replay, layouts, labels containing spaces/punctuation, locations and format round-trips. Review and accept only the new snapshots; existing outputs must stay fixed.
The Latin rectangle test also checks the additive
row/column/treatment model rank independently with
model.matrix() and qr(). Its two-row case is
saturated, so the help explicitly warns that residual variation cannot
be estimated from that model. It is not advertised as a uniformly
sampled Latin rectangle, an optimized design, or a balanced
incomplete-block design.
Expose the design in the app
The scientific engine does not depend on the app. To add a page, supply these declarations/adapters; do not copy a server module:
| File | Addition |
|---|---|
R/app_registry.R |
Label, navigation group, engine, module/spec key and a unique server order |
R/app_design_specs.R |
Shared controls, upload shape, values and the existing classic/spatial workflow family |
R/app_design_args.R |
Plain design_args_<key>(values, data) mapping to
public API arguments; use exact [[ lookup and numeric
normalization |
R/app_classic_workflow_registry.R or spatial
equivalent |
Output identifiers, layout choices, table/heatmap columns, simulation and export settings |
The shared mod_design_ui() and
mod_design_server() do not change. Tests must compare
raw-control and uploaded-data paths against direct API calls, construct
the UI without starting a server, and verify that every registry entry
uses the generic module. Do not commit Shiny server or browser tests.
Manually verify a real session, invalid-input recovery, simulation and
downloads before release. Help topics are derived from the app registry;
do not maintain a second list.
Add an import/export format
Add a reviewed entry to fieldhub_format_registry() in
R/io_design_formats.R: extension, media type, positive
format version, reader and/or writer. A missing reader means write-only.
Public design_formats(), read_design() and
write_design() dispatch from these declarations and need no
new branches.
Readers must return a complete recorded result that passes the common schema and known-engine validator. Parse data, never execute source. Writers receive a validated result and a temporary filename, not the user’s final destination. Version incompatible format changes and define whether old versions are read, migrated or rejected. Do not call a bare CSV table lossless if labels, classes, parameters or RNG settings cannot be recovered from it.
Add round-trip checks across every engine, malformed/truncated/unknown-version fixtures, path and overwrite guards, and assertions that imports do not consume randomness or reconstruct the experiment. Preserve existing destinations on serialization failure. Optional new-format dependencies belong in Suggests with an actionable dependency condition; no automatic installation.
Review checklist
Run the scoped tests first, then the complete plain-R suite and macOS
goldens, full package check with vignettes, changed-line lint and
unchanged core coverage gate. Use the release benchmark comparison when
scientific/engine work changes. Update both NEWS files, reference
validation, architecture guidance and examples. Check minimal-dependency
installation so script users do not require Shiny. Record actual local
and CI evidence separately; consult RELEASING.md before
publishing or assigning a release tag.