NEWS
siera 0.5.6 (2026-06-17)
- Fixed analyses using the wrong population.
readARS() used to apply only the first analysis's analysis set to a whole output, and picked the dataset to merge the population onto from the third analysis. Now every analysis uses the population its own analysisSetId declares, and the merge dataset comes from the analysis's own metadata. In the eTFL disposition table (fda-ds-t04), the per-protocol row now reports 81 / 74 / 79 subjects instead of the All Subjects counts 84 / 84 / 86. Outputs with fewer than three analyses (e.g. a big N plus one content analysis), which used to stop with "invalid 'replacement' argument", now generate normally. Big N analyses still count every subject in the population, wherever they sit in the output, including a second big N for a Total column. Generated scripts change in two visible ways. In outputs drawn only from ADSL, analyses now start from df_poptot rather than df_pop (identical data, so the results are unchanged). An output with several analysis sets names each population after its set (e.g. df_poptot__AnalysisSet_07), and method templates that refer to df_poptot, such as risk differences, use their own analysis's population (#197).
- Fixed
readARS() aborting with "object 'condition_dataset' not found" when an analysis set has no condition, such as an "All Subjects" population. A set without a condition is valid ARS and is now read as the whole dataset, unfiltered: ADSL when any of the set's analyses uses ADSL (otherwise the first analysis's dataset, with a warning if it must be merged onto other datasets), merged onto content datasets like any other population. Analysis sets defined by a compoundExpression are still not supported and keep their existing warning (#200).
- Added CDISC Dataset-JSON (v1.1) export of generated ARDs.
readARS(..., output_format = "datasetjson") appends a section to each generated ARD_<OutputId>.R script that, when the script runs, writes the ARD to ARD_<OutputId>.json beside the script. cards list-columns are flattened (stat to numeric, warning/error to text) and each column gets a variable label from a built-in dictionary of siera and cards columns, falling back to the column name. The optional datasetjson package must be installed where the script runs; without it the export is skipped with a message (#160). A new column_labels argument lets you supply your own labels as a named character vector, e.g. c(TRT01A = "Actual Treatment"); these take precedence over the built-in labels, and a name that matches no ARD column triggers a warning when the script runs (#165). A new vignette, "Exporting ARDs as Dataset-JSON", walks through the feature (#164).
- Added formatted results to generated ARDs. Each ARD row now carries
res (the raw statistic flattened to numeric), pattern (the ARS resultPattern for the row's operation) and disp (the printable, table-ready formatted value, e.g. (N=86), honouring the pattern's decimal count and prefix/suffix). cards proportions (stat_name == "p") are multiplied by 100 before formatting, matching the percentage semantics of result patterns. Rounding follows the clinical-reporting norm of rounding halves away from zero (the SAS ROUND() convention, e.g. 1.369 becomes 1.4 and 2.5 becomes 3) rather than R's default round-half-to-even, so disp aligns with SAS-generated reference tables; the raw res value is left unrounded. The cards-internal fmt_fun/fmt_fn format-function list-columns, which previously surfaced as unprintable values, are dropped from the final ARD (#167).
- Added support for resolving a method's code template from an external reference instead of inline ARS metadata. When a method's
codeTemplate carries a documentRef (rather than inline code), readARS() now follows the ARS referenceDocuments chain to load the template - and, where the method declares none inline, its parameters - from either a siera method manifest (a .json superset of method.json carrying templateCode + parameters, with a method selected by a pageRefs named destination = the method id) or a bare .R/.txt code file. Resolution is transparent: a documentRef ARS generates the same script as its inline equivalent. The whole method library now also ships as one referenceable catalog, inst/method-library/method-library.json, and new bundled examples (exampleARS_5_documentref.json/.xlsx + exampleARS_methods.json) demonstrate the mechanism. v1 resolves local paths only (relative to the ARS file, or absolute); remote URLs are rejected. JSON and XLSX inputs are supported with parity (via the XLSX ReferenceDocuments and AnalysisMethodDocumentRefs sheets) (#175).
- Added
method_library(), an exported accessor that lists the bundled analysis-method templates and resolves a method's files on disk (parallel to ARS_example()).
- Added a plain-text, testable analysis-method template library under
inst/method-library/ (one method.json + template.R per method, plus a reconciled constructs.json valueSource registry and a generated METHODS.md catalog). This becomes the reviewable, diff-able source of truth for the code-template recipes that drive ARD generation; its method ids are intended as stable keys an ARS file can reference. A contract test validates every recipe on each run (templates parse, only supported valueSources are referenced, no orphan tokens, no duplicated case_when mappings, and the human-readable catalog stays in sync). Introduced an internal .supported_value_sources() helper as the declared valueSource contract. The legacy inst/extdata/R_siera_codes.xlsx and cards_constructs.xlsx are left untouched (#173).
- Added support for per-category risk differences. A new method template computes one risk difference and 95% confidence interval for each data-driven inner category (e.g. one per preferred term or system organ class) by looping over the second grouping and calling
cardx::ard_stats_prop_test() within each, instead of collapsing the analysis to a single overall risk difference (#157).
- Added per-category risk differences for pre-defined (non-data-driven) inner groupings. A new method template,
risk_difference_per_predefined_group, honours the groups declared in the ARS metadata instead of looping observed data values: every defined group is emitted - a group whose condition matches no events yields a risk difference of 0 with a [0, 0] confidence interval - and data values matching no defined group are excluded. It is driven by a new AG_var2_group_values valueSource that resolves the second grouping's group condition values, in group order (single-value EQ conditions; other comparators are skipped with a warning). Validated on the eTFL "Overview of Adverse Events" table (one risk difference per action taken and per severity) against an independent stats::prop.test() recomputation; the published reference matches on category shape and empty groups, but its non-zero values were found to be computed from only the first adverse-event record per subject rather than from all qualifying events, so they are not used as the value oracle (#171).
- Added categorical
n (%) summaries that aggregate per pre-defined group condition. A new method template, categorical_summary_per_predefined_group, reports the groups an ARS analysisGrouping declares rather than the values the data happens to contain: every defined group is emitted for every treatment arm - a group no subject reaches is reported as 0 (0.0) instead of being dropped - and data values satisfying no defined group are excluded instead of appearing as rows with missing group identifiers. Because it matches on the group's condition, a group defined by a multi-value IN condition is now one row rather than being unrepresentable. It is driven by two new valueSources, AG_var2_group_conditions and AG_var2_group_levels (EQ and IN conditions; other comparators are skipped with a warning). Use it where the inner grouping is dataDriven: false; categorical_summary remains correct for data-driven groupings, where the data is the category list. Validated on the eTFL "Overview of Adverse Events" table (subjects by treatment and action taken) against an independent distinct-subject recomputation, matching the published reference's row set exactly (#187, and the pre-defined half of #100).
- Added a chi-square test over pre-defined group conditions. A new method template,
chisq_per_predefined_group, compares treatment arms over the groups an ARS analysisGrouping defines rather than over the raw values of the variable, so the p-value belongs to the same categories the n (%) rows of categorical_summary_per_predefined_group report. A group defined by a multi-value IN condition is one category - e.g. age < 65 vs >= 65 (AGEGR1 IN ("65-80", ">80")) gives p = 0.4239, where testing the three AGEGR1 values gives 0.1439 - and values satisfying no defined group are excluded. It reuses the AG_var2_group_conditions valueSource; for groupings whose groups are one-to-one with data values it equals chisq (#215).
- Added per-(category x category) risk differences for analyses with two data-driven inner groupings, such as one risk difference per system organ class and preferred term combination. A new method template,
risk_difference_per_group_pair, loops the distinct combinations of the second and third grouping variables observed in the analysis subset, computes each risk difference with cardx::ard_stats_prop_test(), and stamps both category levels onto the ARD rows. It reuses the existing AG_var3 valueSource, so no change to readARS() was required. Validated on the eTFL "Adverse Events by System Organ Class and Preferred Term" table against an independent stats::prop.test() recomputation over every observed combination (#172).
- Fixed data subsets whose single top-level condition is a multi-value
IN or NOTIN silently filtering on the wrong values when read from JSON. The value list was collapsed into one string, so an IN subset selected no records and a NOTIN subset excluded none (e.g. "AEs leading to dose modification", AEACN NOTIN ["NOT APPLICABLE", "DOSE NOT CHANGED"], counted every subject with any AE). The JSON path now matches the XLSX path, which was unaffected (#211).
- Fixed multi-value
IN and NOTIN conditions read from xlsx ARS files silently dropping records. A cell such as POSSIBLE | PROBABLE (the " | " separator used by TFL Designer and CDISC's excel2ars.py) was split into "POSSIBLE " (with a trailing blank) and "PROBABLE", so every value but the last matched nothing. This affected data subsets and pre-defined group conditions: in the bundled Common Safety Displays example, subjects with a drug-related treatment-emergent adverse event were counted as 23/50/49 instead of 43/70/72. Each value is now trimmed; JSON input was not affected (#213).
- Fixed
readARS() aborting on xlsx ARS files whose methods carry documentation references. The AnalysisMethodDocumentRefs sheet holds a method's documentation references (e.g. a SAP section) as well as its code-template reference, and every row was resolved as a code template - so a method resolved from a method library failed with "location does not exist: ./sap.pdf" whenever its documentation row came first. Rows with referenceType Documentation are now ignored by code generation (#214).
- Fixed
readARS() failing on ARS JSON that writes some condition values as a single value ("value": "Y") and others as an array ("value": ["A", "B"]). jsonlite read the two forms into different column types and combining the data subsets aborted; both forms are now read, whichever tool wrote the file (#217).
- Fixed
readARS() aborting on ARS JSON that writes an empty array for an operation's referencedOperationRelationships or an analysis's referencedAnalysisOperations. Both are valid ARS, and [] is now read as "no relationships", exactly like an absent field (#230).
- Changed the bundled demo reporting event
Common_Safety_Displays_cards.json (used by the README, the vignettes and ARD_script_example("ARD_Out14-1-1.R")) so its demographics output follows its own ARS groupings. The age group, sex, ethnicity and race n (%) analyses use a new method, Mth01_CatVar_Summ_ByPreGrp, with the categorical_summary_per_predefined_group template, and the chi-square tests use chisq_per_predefined_group. The ARD now reports the defined age groups < 65 and >= 65 (AGEGR1 IN 65-80, >80: 72 / 73 / 76 subjects, previously the three AGEGR1 categories), all nine defined race groups (zero-filled where no subject has that race, previously only the three observed), a group id on every row, and the age-group chi-square over the two defined groups (p = 0.4239, previously 0.1439 over the three categories). The deprecated xlsx twin is unchanged (#216).
- Changed the categorical n (%) template (
categorical_summary in the method library, and the demo reporting event's adverse-event analyses) so its result rows carry the ARS analysis variable in variable (e.g. USUBJID, with variable_level NA) instead of the internal counting column dummy / dummyvar. Statistic values are unchanged (#231).
- Changed the level of a pre-defined group in the per-group-condition templates (
categorical_summary_per_predefined_group, its overall variant and chisq_per_predefined_group) from the group's first condition value to its ARS group name. A group covering several values now reads as one category: the demo's age group AGEGR1 IN ("65-80", ">80") is labelled ≥ 65 years rather than 65-80, and single-value groups carry their names too (Male rather than M). Group ids and statistics are unchanged. Generated scripts write such names as portable string literals, with line breaks and non-ASCII characters escaped (#232).
- Fixed zero-event risk-difference analyses returning
NA instead of 0. Methods that compute over the full population (templates referencing df_poptot, e.g. risk differences) now bypass the empty-data subset guard, so an analysis with no events emits the conventional risk difference of 0 with a [0, 0] confidence interval (#156).
- Accepted SAS transport (
.xpt) ADaM datasets in addition to CSV. readARS() chooses the reader for each ADaM dataset from its file extension (.csv via readr::read_csv(), .xpt via haven::read_xpt()), with no new argument; the file lookup is case-insensitive so lower-case submission file names (e.g. adsl.xpt) match upper-case ARS dataset names. Reading .xpt requires the haven package.
- Fixed
readARS() crash when ARS metadata contains no referencedAnalysisOperations (continuous-only tables such as shift tables) by ensuring accumulator frames are initialised with their merge key columns.
- Normalised Windows backslashes in ADaM file paths to forward slashes so generated scripts run correctly on both Windows and Unix systems.
- Added CDISC ARD-compliant column stamping: generated scripts now write
group[n]_groupingId, group[n]_groupId (for pre-defined groups) and group[n]_groupValue (for data-driven groupings) onto each ARD row.
- Supported arbitrarily deep nesting in
mainListOfContents via a recursive LOPA extraction helper, removing the previous three-level hard limit.
- Expanded support for multi-value ARS group conditions (
IN/NOTIN) by unnesting condition.value list columns in the JSON parser.
- Coerced
*_level columns to character on each individual ARD frame before bind_rows, preventing type conflicts between continuous and categorical analyses.
- Allowed more than three grouping factors per analysis.
- Updated bundled
cards_constructs.xlsx example file and extended test coverage across metadata parsing, ADaM loading, and ARD script generation.
siera 0.5.5 (2025-12-01)
- Strengthened analysis method validation with clear errors for missing or undefined
MethodId values and warnings when method templates or parameter value sources cannot be resolved.
- Added guardrails for analysis set generation that warn on missing or incomplete metadata and fall back to the unfiltered analysis dataset when needed.
- Tightened ARS metadata ingestion by requiring
analysisSets definitions in JSON and the analysis code template sheets in Excel workbooks.
- Expanded test coverage for analysis methods, analysis sets, and data subset condition handling to capture more metadata edge cases.
siera 0.5.4 (2025-09-25)
- Comprehensive testing added: checking generated ARD result values
- added warning messages with cli()
- cover scenarios for bigN vs table-level subsetting
siera 0.5.3 (2025-08-28)
- Cover scenario of multi-value DataSubsets
- Cover scenario of overlapping variables in ADSL merge
siera 0.5.2 (2025-08-25)
- Added conditional operators to cover EQ, NE, GE, GT, LE, LT
siera 0.5.0 (2025-07-29)
- readARS function to ingest xlsx, json and CDISC example
siera 0.4.0 (2025-07-18)
- addition of readARS_xl function
- example added of {cards} in AnalysisMethodCodeTemplate
siera 0.3.0 (2025-03-03)
- dynamic recognition of ADaMs
siera 0.1.0 (2025-02-10)