Quality / tfl-engine

Engine

TFL Engine — evidence

The R package that turns ADaM into ARDs and ARDs into displays: data-prep, the analysis.yaml interpreter, the owned ard.json serialization, and the gt/tfrmt/r2rtf renderers.

62reviewed requirementstfl-engine.md
74test recordsr-unit
0failing74 passing
94%requirement coverage58/62 evidenced

Requirements

IDAreaRequirementEvidence typeResult
TFL-PREP-001prepare_data() excludes all screen-failure subjects (ARM == "Screen Failure") from ADSL and restricts every other prepared dataset to the surviving subjects.1 passing
TFL-PREP-002ITTFL is derived from randomisation (!is.na(RANDDT)); SAFFL is used as shipped with NA recoded to "N".1 passing
TFL-PREP-003COMPLFL and the derived DISCREAS reproduce EOSSTT exactly and partition the discontinued subjects.1 passing
TFL-PREP-004Baseline weight, height and BMI are merged onto ADSL from the ADVS records flagged ABLFL == "Y", so display code never joins subject-level data.1 passing
TFL-PREP-005Every prepared dataset is described in a manifest with row/column counts, a SHA-256 content hash, and the source package and version.1 passing
TFL-PREP-006The analysis-set registry maps analysis_set keys onto population flags and rejects unknown sets and datasets lacking the required flag.1 passing
TFL-PREP-007Treatment arms are ordered by dose, not alphabetically, in every prepared dataset.1 passing
TFL-SPEC-001An analysis method outside the documented vocabulary is rejected, naming the offending analysis and listing the known methods.1 passing
TFL-SPEC-002Missing required keys and missing per-method fields (variables, hierarchy, custom) are rejected before any {cards} call is attempted.2 passing
TFL-SPEC-003A display specification must carry a study identifier, a population label and a data cut-off — the ICH E3 header requirement — as non-empty strings.1 passing
TFL-SPEC-004Row-plan keys that YAML 1.1 silently coerces to booleans (bare n, y, no, on, off) are rejected with an explanation rather than rendered as FALSE.1 passing
TFL-SPEC-005A display row referencing an analysis the analysis spec does not define, or an id mismatch between the two specs, fails the build.1 passing
TFL-SPEC-006Every display committed to library/tfl/ validates, has matching ids, and declares a post_text variant.1 passing
TFL-ARD-001build_ard() emits one row per computed statistic, carrying the analyses[].name that produced it, and its continuous statistics equal a direct dplyr computation.2 passing
TFL-ARD-002subject_count counts distinct subjects over the analysis-set subject denominator, never over event records.1 passing
TFL-ARD-003hierarchical_count nests inner terms under their outer level, counts each subject once per level, and matches a direct dplyr computation.1 passing
TFL-ARD-004The total column is computed by the same code path as the treatment columns and is labelled with the grouping variable, not an internal constant.1 passing
TFL-ARD-005listing passes records through as one ARD row per record per listed variable, addressable by record index.1 passing
TFL-ARD-006An analysis may dispatch to a function in the display's custom.R; a missing custom function is a build failure, not a silent skip.1 passing
TFL-ARD-007An analysis filter restricts the records summarised, and a filter that is not one logical per row or references an unknown variable fails loudly.1 passing
TFL-ARD-008{cards}' per-statistic warning and error values are retained as ARD columns; statistics computed on empty groups are recorded, not dropped.1 passing
TFL-ARD-009A binding address resolves to exactly one ARD row; zero or multiple matches raise an error.1 passing
TFL-QNT-001Quartiles use the SAS-compatible type-2 quantile definition, not R's default type 7.1 passing
TFL-IO-001ard.json conforms to the owned schema: schema, display, created, provenance, rows, with the full thirteen-key row shape on every row.1 passing
TFL-IO-002The provenance envelope records spec and display hashes, per-dataset hashes and versions, the R and package environment, and the git commit.1 passing
TFL-IO-003write_ard() / read_ard() round-trip an ARD without loss; numeric statistics stay numeric.1 passing
TFL-IO-004Reading refuses a document that is not an opencsr/ard/v1 ARD; writing refuses rows missing schema columns.1 passing
TFL-IO-005Every committed ARD is readable, names only analyses its spec defines, and carries no statistic-level errors.1 passing
TFL-FMT-001Rounding is half away from zero (SAS behaviour), not R's round-half-to-even, and is stable against binary representation error.3 passing
TFL-FMT-002Proportions are scaled to percent and every statistic is rendered at its declared precision, including trailing zeros.2 passing
TFL-FMT-003The digit plan is declarative: a display-level plan applies by default and a row-level plan overrides it for variables with different collected precision.2 passing
TFL-RND-001Rendered HTML is a standalone document with inline CSS and no external stylesheet, script or CDN reference.1 passing
TFL-RND-002In-text and post-text variants render from one ARD; the in-text variant is a strict subset of the post-text variant and applies the declared percentage threshold exactly.2 passing
TFL-RND-003Columns follow the declared order, carry group headcounts, and silently omit declared columns absent from the ARD.1 passing
TFL-RND-004Every rendered display states its study, its analysis set and its data cut-off, and carries a source line.1 passing
TFL-RND-005Rendering a variant the display does not declare is an error.1 passing
TFL-RND-006Section headings left without data rows are dropped, and indentation distinguishes headings from the rows beneath them.1 passing
TFL-RND-007A listing renders one column per listed variable with the label declared in the display spec.1 passing
TFL-ITER-001regenerate() writes a complete iteration directory — spec snapshots, ard.json, rendered variants and a manifest — with spec snapshots byte-identical to the specs read.1 passing
TFL-ITER-002The iteration manifest records the actor, the change request, the regulatory identifier, the ARD hash, row counts, error counts, the rendered variants and the environment.1 passing
TFL-ITER-003A second regeneration — whether through regenerate() or regenerate_all() — allocates a new version and never overwrites an earlier one; current.json moves and the ledger grows.1 passing
TFL-ITER-004Version allocation takes the maximum of the filesystem and the ledger, so a partially written or partially deleted iteration cannot be silently overwritten.1 passing
TFL-ITER-005The committed t-ae-common ledger records a real two-iteration change-request story: differing spec and ARD hashes, a recorded request and actor, and unchanged values for the numbers the change did not touch.1 passing
TFL-ITER-006Regenerating a display whose spec id does not match its directory is an error.1 passing
TFL-ITER-007Every display in the library has a current iteration on disk, referenced by both current.json and the ledger.1 passing
TFL-RTF-001A rendered display encodes as a complete RTF document.1 passing
TFL-RTF-002Every cell of the rendered display appears in the RTF, and row labels arrive without the non-breaking-space indentation the HTML renderer uses.2 passing
TFL-RTF-003The display title, population label, footnotes, source line and column headers with their subject counts travel into the RTF.2 passing
TFL-RTF-004Listings and reduced in-text variants render as RTF as well as full summary tables do, each naming the variant it is.2 passing
TFL-RTF-005regenerate() writes an RTF beside every rendered variant and records its filename and sha256 in the iteration manifest.2 passing
TFL-RTF-006Every committed display has an RTF for each variant whose hash matches the manifest, so a hand-edited artifact fails the build.1 passing
TFL-VAL-001The values declaration validates: unique ids, a readable label on every value, and exactly one of an ARD source or a declared derivation.2 passing
TFL-VAL-002A malformed binding address or an operation outside the closed vocabulary is rejected with a message naming the value.1 passing
TFL-VAL-003Every ARD-sourced value equals its row in the committed ARD and carries that iteration's path and sha256.2 passing
TFL-VAL-004A derived value equals the arithmetic it declares over values defined before it; a forward reference is an error.2 passing
TFL-VAL-005A binding that resolves to no ARD row, or names a display with no committed iteration, fails the build rather than producing a blank value.1 passing
TFL-VAL-006Scaling and rounding are presentation only: the stored value stays the ARD's, and formatted carries the display format.1 passing
TFL-VAL-007The committed store matches a fresh build of the declaration, value for value.1 passing
TFL-QC-001Every testthat test name matches <REQ-ID>[, <REQ-ID>]: <description> (#<issue>).no test
TFL-QC-002Every requirement ID cited by a test exists in a matrix under quality/requirements/.no test
TFL-QC-003Every requirement in a matrix is cited by at least one test — no untested claims.no test
TFL-QC-004Requirement matrices use the five columns ID, Requirement, Type, Verification and Status, with five cells on every requirement row.no test

Test records

ResultSuiteTestRequirementsFile
passr-unitDSP-ALL-001: every display renders a table that actually contains numbers (#1)DSP-ALL-001test-displays.R
passr-unitDSP-ALL-002: every display declares a regulatory identifier and a source line (#1)DSP-ALL-002test-displays.R
passr-unitTFL-ARD-001: build_ard returns one row per computed statistic, tagged with its analysis (#1)TFL-ARD-001test-ard-build.R
passr-unitTFL-ARD-001: continuous statistics equal a direct dplyr computation (#1)TFL-ARD-001test-ard-build.R
passr-unitTFL-ARD-002: subject_count uses the analysis-set subject denominator (#1)TFL-ARD-002test-ard-build.R
passr-unitTFL-ARD-003: hierarchical_count nests preferred terms under their SOC (#1)TFL-ARD-003test-ard-build.R
passr-unitTFL-ARD-004: the total column is produced by the same code path as the arms (#1)TFL-ARD-004test-ard-build.R
passr-unitTFL-ARD-005: listing passes records through as one row per variable (#1)TFL-ARD-005test-ard-build.R
passr-unitTFL-ARD-006: an analysis may dispatch to a function in custom.R (#1)TFL-ARD-006test-ard-build.R
passr-unitTFL-ARD-007: an analysis filter restricts the records it summarises (#1)TFL-ARD-007test-ard-build.R
passr-unitTFL-ARD-008: cards' per-statistic warning and error columns survive into the ARD (#1)TFL-ARD-008test-ard-build.R
passr-unitTFL-ARD-009: a binding address must resolve to exactly one ARD row (#1)TFL-ARD-009test-ard-build.R
passr-unitTFL-FMT-001: round_half_up preserves NA, Inf and vector length (#1)TFL-FMT-001test-formatting.R
passr-unitTFL-FMT-001: round_half_up rounds half away from zero, unlike base::round (#1)TFL-FMT-001test-formatting.R
passr-unitTFL-FMT-001: round_half_up survives binary representation error (#1)TFL-FMT-001test-formatting.R
passr-unitTFL-FMT-002: format_stat applies the collected-precision defaults (#1)TFL-FMT-002test-formatting.R
passr-unitTFL-FMT-002: format_stat scales proportions to percent and pads decimals (#1)TFL-FMT-002test-formatting.R
passr-unitTFL-FMT-003: format_stat honours an explicit digit plan (#1)TFL-FMT-003test-formatting.R
passr-unitTFL-FMT-003: the row-level digit plan overrides the display digit plan (#1)TFL-FMT-003test-formatting.R
passr-unitTFL-IO-001: ard.json matches the owned schema, top to bottom (#1)TFL-IO-001test-ard-io.R
passr-unitTFL-IO-002: the provenance envelope is complete and machine-checkable (#1)TFL-IO-002test-ard-io.R
passr-unitTFL-IO-003: write_ard / read_ard round-trip an ARD without loss (#1)TFL-IO-003test-ard-io.R
passr-unitTFL-IO-004: reading refuses a document that is not an opencsr ARD (#1)TFL-IO-004test-ard-io.R
passr-unitTFL-IO-005: every committed ARD is readable and internally consistent (#1)TFL-IO-005test-ard-io.R
passr-unitTFL-ITER-001: regenerate writes a complete, self-describing iteration (#1)TFL-ITER-001test-regenerate.R
passr-unitTFL-ITER-002: the manifest records who, why, from what and how many (#1)TFL-ITER-002test-regenerate.R
passr-unitTFL-ITER-003: a second regeneration never overwrites the first (#1)TFL-ITER-003test-regenerate.R
passr-unitTFL-ITER-004: version allocation is robust to ledger and filesystem drift (#1)TFL-ITER-004test-regenerate.R
passr-unitTFL-ITER-005: the committed t-ae-common ledger tells a two-iteration change-request story (#1)TFL-ITER-005test-regenerate.R
passr-unitTFL-ITER-006: regenerate refuses specs whose ids disagree with each other or the directory (#1)TFL-ITER-006test-regenerate.R
passr-unitTFL-ITER-007: every display in the library has a current iteration on disk (#1)TFL-ITER-007test-regenerate.R
passr-unitTFL-PREP-001: screen failures are excluded from every prepared dataset (#1)TFL-PREP-001test-data-prep.R
passr-unitTFL-PREP-002: ITTFL is derived from randomisation, SAFFL is used as shipped (#1)TFL-PREP-002test-data-prep.R
passr-unitTFL-PREP-003: COMPLFL and DISCREAS reconstruct EOSSTT exactly (#1)TFL-PREP-003test-data-prep.R
passr-unitTFL-PREP-004: baseline vitals are merged from ADVS onto ADSL (#1)TFL-PREP-004test-data-prep.R
passr-unitTFL-PREP-005: the manifest describes every prepared dataset with a sha256 hash (#1)TFL-PREP-005test-data-prep.R
passr-unitTFL-PREP-006: the analysis-set registry rejects unknown sets and applies flags (#1)TFL-PREP-006test-data-prep.R
passr-unitTFL-PREP-007: treatment arms are ordered by dose, not alphabetically (#1)TFL-PREP-007test-data-prep.R
passr-unitTFL-QNT-001: quartiles follow the SAS-compatible type-2 definition (#1)TFL-QNT-001test-ard-build.R
passr-unitTFL-RND-001: rendered HTML is standalone — no CDN, no script, no external asset (#1)TFL-RND-001test-render.R
passr-unitTFL-RND-002: the 5% threshold keeps exactly the terms that reach it (#1)TFL-RND-002test-render.R
passr-unitTFL-RND-002: the in-text variant is a strict subset of the post-text variant (#1)TFL-RND-002test-render.R
passr-unitTFL-RND-003: columns follow the declared order and carry group counts (#1)TFL-RND-003test-render.R
passr-unitTFL-RND-004: every display states study, analysis set and data cut-off (#1)TFL-RND-004test-render.R
passr-unitTFL-RND-005: rendering rejects a variant the display does not declare (#1)TFL-RND-005test-render.R
passr-unitTFL-RND-006: section headings without data rows are dropped, indentation is preserved (#1)TFL-RND-006test-render.R
passr-unitTFL-RND-007: a listing renders one column per listed variable with its label (#1)TFL-RND-007test-render.R
passr-unitTFL-RTF-001: a rendered display encodes as a complete RTF document (#1)TFL-RTF-001test-rtf.R
passr-unitTFL-RTF-002: every cell of the rendered display survives into the RTF (#1)TFL-RTF-002test-rtf.R
passr-unitTFL-RTF-002: row labels arrive without the HTML indentation trick (#1)TFL-RTF-002test-rtf.R
passr-unitTFL-RTF-003: column headers carry the treatment arms and their subject counts (#1)TFL-RTF-003test-rtf.R
passr-unitTFL-RTF-003: the title, population, footnotes and source line travel with the table (#1)TFL-RTF-003test-rtf.R
passr-unitTFL-RTF-004: a listing renders as RTF as well as a summary table does (#1)TFL-RTF-004test-rtf.R
passr-unitTFL-RTF-004: the in-text variant renders its own, smaller RTF (#1)TFL-RTF-004test-rtf.R
passr-unitTFL-RTF-005: regenerate writes an RTF beside every rendered variant (#1)TFL-RTF-005test-rtf.R
passr-unitTFL-RTF-005: the manifest records each variant's RTF and its hash (#1)TFL-RTF-005test-rtf.R
passr-unitTFL-RTF-006: every committed display has an RTF whose hash matches its manifest (#1)TFL-RTF-006test-rtf.R
passr-unitTFL-SPEC-001: an unknown analysis method is rejected by name (#1)TFL-SPEC-001test-spec-validation.R
passr-unitTFL-SPEC-002: missing required analysis keys are reported together (#1)TFL-SPEC-002test-spec-validation.R
passr-unitTFL-SPEC-002: per-method required fields are enforced (#1)TFL-SPEC-002test-spec-validation.R
passr-unitTFL-SPEC-003: a display must identify its study, population and data cut-off (#1)TFL-SPEC-003test-spec-validation.R
passr-unitTFL-SPEC-004: bare YAML `n` read as a boolean is rejected with an explanation (#1)TFL-SPEC-004test-spec-validation.R
passr-unitTFL-SPEC-005: a display row naming an unknown analysis fails the build (#1)TFL-SPEC-005test-spec-validation.R
passr-unitTFL-SPEC-006: every committed display in the library validates (#1)TFL-SPEC-006test-spec-validation.R
passr-unitTFL-VAL-001: a declaration missing a label, an id or a source is rejected (#1)TFL-VAL-001test-values.R
passr-unitTFL-VAL-001: the committed declaration validates and every value is uniquely named (#1)TFL-VAL-001test-values.R
passr-unitTFL-VAL-002: a malformed binding address or unknown operation is rejected (#1)TFL-VAL-002test-values.R
passr-unitTFL-VAL-003: every ARD-sourced value equals its row in the committed ARD (#1)TFL-VAL-003test-values.R
passr-unitTFL-VAL-003: every value carries the iteration and hash of the ARD it came from (#1)TFL-VAL-003test-values.R
passr-unitTFL-VAL-004: a derivation naming a value declared after it is an error (#1)TFL-VAL-004test-values.R
passr-unitTFL-VAL-004: a derived value equals the arithmetic it declares (#1)TFL-VAL-004test-values.R
passr-unitTFL-VAL-005: an unresolvable binding fails the build rather than producing a blank value (#1)TFL-VAL-005test-values.R
passr-unitTFL-VAL-006: percentages are scaled and rounded at presentation, never in the store (#1)TFL-VAL-006test-values.R
passr-unitTFL-VAL-007: the committed store matches a fresh build of the declaration (#1)TFL-VAL-007test-values.R

Traceability

No generated output yet, so the data → ARD → display chain is empty.

Provenance

Generated
2026-07-27T04:44:02.378Z
Environment
os Darwin 23.6.0 · node v24.14.0 · vitest 2.1.9 · r 4.3.3
CI run
Not recorded for this evidence set