cttiR creates a scaffold from a name, research type and goal. The current implementation records unresolved scientific decisions and provides a reviewed layout adaptation, catalog evidence and transactional maintenance. It does not yet implement the complete research workflow or confer scientific approval.
path is the existing parent directory.
Creation uses a portable child name. A preview does not create the child
or install dependencies.
plan <- cttiR::project(
"Example comparison", "methods", "Plan a reproducible tabular comparison",
path = example_root, dry_run = TRUE
)
plan$spec$project[c("name", "slug", "type")]
#> $name
#> [1] "Example comparison"
#>
#> $slug
#> [1] "example_comparison"
#>
#> $type
#> [1] "methods"
plan$readiness
#> $level
#> [1] "scaffold_ready"
#>
#> $materialized
#> [1] FALSE
#>
#> $blockers
#> [1] "environment_pending" "capability_gaps_recorded"
#>
#> $analysis
#> $analysis$state
#> [1] "incomplete"
#>
#> $analysis$candidate_engine
#> NULL
#>
#> $analysis$requested_engine
#> NULL
#>
#> $analysis$missing_fields
#> $analysis$missing_fields[[1]]
#> [1] "/analysis/outcome_family"
#>
#> $analysis$missing_fields[[2]]
#> [1] "/analysis/unit_structure"
#>
#> $analysis$missing_fields[[3]]
#> [1] "/analysis/mapping/data_source_id"
#>
#> $analysis$missing_fields[[4]]
#> [1] "/analysis/mapping/estimand"
#>
#> $analysis$missing_fields[[5]]
#> [1] "/analysis/mapping/missing_data"
#>
#> $analysis$missing_fields[[6]]
#> [1] "/analysis/approved"
#>
#>
#> $analysis$capability_gaps
#> list()
#>
#> $analysis$model
#> $analysis$model$state
#> [1] "incomplete"
#>
#> $analysis$model$settings
#> NULL
#>
#> $analysis$model$missing_fields
#> $analysis$model$missing_fields[[1]]
#> [1] "/analysis/model/reviewed"
#>
#>
#> $analysis$model$inapplicable_fields
#> list()
#>
#> $analysis$model$capability_gaps
#> $analysis$model$capability_gaps[[1]]
#> [1] "supported_engine_not_selected"
#>
#>
#> $analysis$model$executable
#> [1] FALSE
#>
#> $analysis$model$limitation
#> [1] "Recorded choices do not approve a package revision, model fit or scientific interpretation."
#>
#>
#> $analysis$executable
#> [1] FALSE
#>
#> $analysis$blockers
#> $analysis$blockers[[1]]
#> [1] "adapter_and_revision_approval_pending"
#>
#> $analysis$blockers[[2]]
#> [1] "data_checks_not_run"
#>
#> $analysis$blockers[[3]]
#> [1] "model_settings_incomplete"
#>
#>
#> $analysis$limitations
#> $analysis$limitations[[1]]
#> [1] "Candidate routing is not methodological or workflow approval."
#>
#> $analysis$limitations[[2]]
#> [1] "No dataset is opened and no formula, expression or model is evaluated."
#>
#> $analysis$limitations[[3]]
#> [1] "Column types, levels, missingness, model assumptions and diagnostics require runtime checks."
#>
#>
#>
#> $planning
#> $planning$mode
#> [1] "deterministic"
#>
#> $planning$fallback_reason
#> NULL
#>
#> $planning$local_runtime
#> [1] "not_checked"
#>
#> $planning$guidance
#> [1] "Use setup(dry_run = TRUE) to inspect optional local planning prerequisites."
#>
#>
#> $workflow
#> $workflow$profile
#> [1] "standard_reflowR"
#>
#> $workflow$bundle
#> [1] "standard-0.3.0"
#>
#> $workflow$engine
#> NULL
#>
#> $workflow$modality
#> [1] "unknown"
#>
#> $workflow$stages
#> $workflow$stages[[1]]
#> $workflow$stages[[1]]$stage
#> [1] "project"
#>
#> $workflow$stages[[1]]$capability
#> [1] "std.project.reflowr_layout"
#>
#> $workflow$stages[[1]]$adapter
#> [1] "[email protected]"
#>
#> $workflow$stages[[1]]$enabled
#> [1] TRUE
#>
#> $workflow$stages[[1]]$status
#> [1] "approved"
#>
#>
#> $workflow$stages[[2]]
#> $workflow$stages[[2]]$stage
#> [1] "import"
#>
#> $workflow$stages[[2]]$capability
#> [1] "std.import.delimited"
#>
#> $workflow$stages[[2]]$adapter
#> [1] "[email protected]"
#>
#> $workflow$stages[[2]]$enabled
#> [1] TRUE
#>
#> $workflow$stages[[2]]$status
#> [1] "approved"
#>
#>
#> $workflow$stages[[3]]
#> $workflow$stages[[3]]$stage
#> [1] "check"
#>
#> $workflow$stages[[3]]$capability
#> [1] "std.check.mapped"
#>
#> $workflow$stages[[3]]$adapter
#> [1] "[email protected]"
#>
#> $workflow$stages[[3]]$enabled
#> [1] TRUE
#>
#> $workflow$stages[[3]]$status
#> [1] "approved"
#>
#>
#> $workflow$stages[[4]]
#> $workflow$stages[[4]]$stage
#> [1] "tidy"
#>
#> $workflow$stages[[4]]$capability
#> [1] "std.tidy.dplyr"
#>
#> $workflow$stages[[4]]$adapter
#> [1] "[email protected]"
#>
#> $workflow$stages[[4]]$enabled
#> [1] TRUE
#>
#> $workflow$stages[[4]]$status
#> [1] "approved"
#>
#>
#> $workflow$stages[[5]]
#> $workflow$stages[[5]]$stage
#> [1] "describe"
#>
#> $workflow$stages[[5]]$capability
#> [1] "std.describe.descrtab2"
#>
#> $workflow$stages[[5]]$adapter
#> [1] "[email protected]"
#>
#> $workflow$stages[[5]]$enabled
#> [1] TRUE
#>
#> $workflow$stages[[5]]$status
#> [1] "approved"
#>
#>
#> $workflow$stages[[6]]
#> $workflow$stages[[6]]$stage
#> [1] "figures"
#>
#> $workflow$stages[[6]]$capability
#> [1] "std.figures.accessible"
#>
#> $workflow$stages[[6]]$adapter
#> [1] "[email protected]"
#>
#> $workflow$stages[[6]]$enabled
#> [1] TRUE
#>
#> $workflow$stages[[6]]$status
#> [1] "approved"
#>
#>
#> $workflow$stages[[7]]
#> $workflow$stages[[7]]$stage
#> [1] "demo"
#>
#> $workflow$stages[[7]]$capability
#> [1] "std.demo.synthetic"
#>
#> $workflow$stages[[7]]$adapter
#> [1] "[email protected]"
#>
#> $workflow$stages[[7]]$enabled
#> [1] TRUE
#>
#> $workflow$stages[[7]]$status
#> [1] "approved"
#>
#>
#> $workflow$stages[[8]]
#> $workflow$stages[[8]]$stage
#> [1] "report"
#>
#> $workflow$stages[[8]]$capability
#> [1] "std.report.render"
#>
#> $workflow$stages[[8]]$adapter
#> [1] "[email protected]"
#>
#> $workflow$stages[[8]]$enabled
#> [1] TRUE
#>
#> $workflow$stages[[8]]$status
#> [1] "approved"
#>
#>
#>
#> $workflow$gaps
#> $workflow$gaps[[1]]
#> [1] "model_requires_outcome_family_and_unit_structure"
#>
#>
#>
#> $environment
#> $environment$state
#> [1] "dependencies_missing"
#>
#> $environment$missing
#> $environment$missing[[1]]
#> [1] "DescrTab2"
#>
#>
#> $environment$mismatched
#> $environment$mismatched[[1]]
#> [1] "colorspace 2.1-4 != 2.1-2"
#>
#> $environment$mismatched[[2]]
#> [1] "grDevices 4.6.2 != 4.6.1"
#>
#> $environment$mismatched[[3]]
#> [1] "knitr 1.52 != 1.51"
#>
#> $environment$mismatched[[4]]
#> [1] "nlme 3.1-172 != 3.1-170"
#>
#> $environment$mismatched[[5]]
#> [1] "rmarkdown 2.32 != 2.31"
#>
#> $environment$mismatched[[6]]
#> [1] "stats 4.6.2 != 4.6.1"
#>
#> $environment$mismatched[[7]]
#> [1] "survival 3.8-12 != 3.8-9"
#>
#> $environment$mismatched[[8]]
#> [1] "tools 4.6.2 != 4.6.1"
#>
#> $environment$mismatched[[9]]
#> [1] "utils 4.6.2 != 4.6.1"
#>
#>
#> $environment$unpinned
#> list()
#>
#> $environment$limitation
#> [1] "Installed versions are read from package metadata; no environment was prepared or restored."
#>
#>
#> $git
#> $git$state
#> [1] "not_requested"
stopifnot(!dir.exists(plan$path))Apply the same request explicitly:
p <- cttiR::project(
"Example comparison", "methods", "Plan a reproducible tabular comparison",
path = example_root
)
stopifnot(dir.exists(p$path))
p$spec$analysis
#> $aim
#> [1] "explanatory"
#>
#> $outcome_family
#> [1] "unknown"
#>
#> $unit_structure
#> [1] "unknown"
#>
#> $engine
#> NULL
#>
#> $approved
#> [1] FALSECreation does not read study data, infer endpoints or ethics
approval, call a model, initialize Git, install packages or render the
report. The configuration and lock record accepted identity and
provenance. The lock is not an renv.lock.
The project contains:
cttir-project.yml: project, research and publication
configuration.cttir-lock.json: accepted catalog, resource and
template pins.metadata/: dataset registry, variable dictionary and
template provenance.protocol/analysis-plan.md: decisions to review before
analysis.analysis/: adapted reflowR pages and a labelled
synthetic rendering fixture.publications/: separate analysis, manuscript, figure,
table and submission trees..cttir/: ownership, state and machine-local data
bindings.Raw data are not copied. Keep sensitive local paths in the ignored
.cttir/local.yml; registry descriptions should be suitable
for the intended repository audience.
An identical creation request preserves the accepted identity and
existing edits. A different request for an occupied project name raises
a conflict; use sync() to preview configuration
changes.
again <- cttiR::project(
"Example comparison", "methods", "Plan a reproducible tabular comparison",
path = example_root
)
stopifnot(identical(again$spec$project$id, p$spec$project$id))
stopifnot(all(again$plan$action == "skip"))options takes precedence over a config list
or YAML/JSON file. Unknown fields are rejected. Updates to publication
and dataset arrays are keyed by identity. Unsupported workflow or
dependency migrations fail explicitly.
preview <- cttiR::sync(p$path, options = list(project = list(language = "de")))
preview$actions[preview$actions$action != "skip", c("path", "action")]
#> path action
#> 2 cttir-project.yml update
#> 37 cttir-lock.json update
#> 38 .cttir/managed-files.json update
#> 39 .cttir/state.json update
#> 40 .cttir/accepted-spec.yml update
stopifnot(preview$state == "planned")
applied <- cttiR::sync(
p$path, options = list(project = list(language = "de")), dry_run = FALSE
)
applied$state
#> [1] "applied"The language setting is metadata; it does not promise that every generated page or interface message is translated. User-owned analysis/manuscript files are preserved. Edited managed files cause a conflict. Applied changes have backups and a journal, but a multi-file update is not one atomic filesystem operation.
Dataset identifiers link the analysis to its registry entry. Column names are literal names, including names containing spaces; they are never parsed as R expressions. Unknown decisions stay visible. This example records an intended continuous-outcome association and leaves approval unresolved:
analysis_config <- list(
data_sources = list(list(
id = "source01", label = "Example registry entry", logical_uri = NULL,
format = "csv", access_class = "unknown", checksum = NULL,
checksum_status = "unknown", schema_ref = NULL
)),
analysis = list(
aim = "explanatory", outcome_family = "continuous",
unit_structure = "independent", engine = "stats::lm", approved = FALSE,
mapping = list(
data_source_id = "source01", outcome = "response",
predictors = list("exposure"), estimand = "A specified conditional association",
missing_data = "fail"
)
)
)
mapped <- cttiR::project(
"Mapping example", "methods", "Record a proposed analysis configuration",
path = example_root, config = analysis_config, dry_run = TRUE
)
mapped$readiness$analysis[c("state", "candidate_engine", "missing_fields", "executable")]
#> $state
#> [1] "incomplete"
#>
#> $candidate_engine
#> [1] "stats::lm"
#>
#> $missing_fields
#> $missing_fields[[1]]
#> [1] "/analysis/approved"
#>
#>
#> $executable
#> [1] FALSE
stopifnot(!mapped$readiness$analysis$executable, !dir.exists(mapped$path))Binary and survival configurations require explicit event/non-event
codes; survival also requires time origin and units. Longitudinal
configurations require subject/time mappings and a separate review of
random effects and residual structure. Predictive, causal and other
unsupported designs remain capability gaps. An explicitly empty
predictor list records an intercept-only intention.
complete_case records a reviewed missing-data intention;
planning never removes rows. Even a fully recorded configuration and
approved = TRUE cannot bypass pending adapter/revision
approval, dataset checks or model diagnostics.
Model choices are recorded separately from data mappings. There are
no inferred intercept, link, tie-handling or random-effects choices.
reviewed = TRUE records the user’s review of those
settings; it does not approve a package revision or scientific
interpretation. Supported candidate settings include a fixed intercept
for linear/binomial/mixed models, a logit link for binary models,
explicit Cox tie handling, and a random intercept with independent
homoscedastic residuals and ML or REML estimation for mixed models. Cox
settings do not include an estimated intercept. More complex structures
remain unsupported.
analysis_config$analysis$model <- list(intercept = TRUE, reviewed = TRUE)
model_draft <- cttiR::project(
"Model settings example", "methods", "Record explicit model choices",
path = example_root, config = analysis_config, dry_run = TRUE
)
model_draft$readiness$analysis$model[c("state", "missing_fields", "executable")]
#> $state
#> [1] "settings_recorded"
#>
#> $missing_fields
#> list()
#>
#> $executable
#> [1] FALSE
stopifnot(model_draft$readiness$analysis$model$state == "settings_recorded",
!model_draft$readiness$analysis$executable)The outer configuration_recorded state describes
variable mapping and analysis intent; the nested model
state reports settings separately. A mapping alone does not satisfy the
model_settings_incomplete readiness blocker. Neither state
makes a project executable while adapter, revision or data checks remain
pending.
Check an explicitly supplied in-memory data frame separately. This does not read registered data locations, modify records or fit a model. Only mapped columns participate in missingness; a configured complete-case policy reports how many rows are complete without deleting them. Event codes are compared as literal text, including factor labels. Data frame subclasses, matrix/list columns and unreviewed date transformations are refused rather than coerced.
synthetic <- data.frame(response = c(2, 4, 6, 8), exposure = 1:4)
data_check <- cttiR::check_analysis_data(synthetic, mapped$spec)
data_check[c("state", "rows_total", "rows_complete", "issues", "executable")]
#> $state
#> [1] "passed"
#>
#> $rows_total
#> [1] 4
#>
#> $rows_complete
#> [1] 4
#>
#> $issues
#> list()
#>
#> $executable
#> [1] FALSE
stopifnot(data_check$state == "passed", !data_check$executable)A passed result covers only the listed structural checks. It does not establish independence, unit correctness, rank, model assumptions, adequate sample size, causal identification or scientific approval. Survival checks currently target positive follow-up times with explicit right-censoring codes; more complex event processes require a different adapter.
The API catalog and resource registry are separate evidence layers. A discovered resource is not automatically installed or approved. An extracted function signature is not proof of scientific suitability.
hit <- cttiR::search("reflowR::reflow_init", path = p$path)
hit[, c("package", "revision", "verification", "approved")]
#> package revision verification approved
#> 1 reflowR cd1243a068ff2c8fb6796e34b58f6c6ce6af87e8 static_api_verified FALSE
answer <- cttiR::ask("reflowR::reflow_init", path = p$path)
stopifnot(identical(answer$code, ""))Literal documentation search can return bounded excerpts from stored, licensed source documents. The initial corpus includes the pinned reflowR revision. Documents are not rendered or executed during indexing. Coverage is reported separately from workflow approval:
known <- cttiR::packages(path = p$path)
known[known$package == "reflowR",
c("package", "documents_discovered", "documents_stored", "approved")]
#> package documents_discovered documents_stored approved
#> 45 reflowR 33 31 0ask(verified_only = TRUE) restricts evidence to
statically resolved API records. It does not yet provide qualified
natural-language planning. The package currently has zero
workflow-approved revisions, so a complete research-ready workflow must
not be inferred from these queries.
The following examples are deliberately not run by the vignette. They show explicit local and public GitHub source registration:
options(cttiR.sources = list(
list(id = "local-tool", path = "/path/to/package-source"),
list(id = "public-reflow", github = "CTTIR/reflowR", package = "reflowR",
ref = "cd1243a068ff2c8fb6796e34b58f6c6ce6af87e8")
))
cttiR::update(dry_run = TRUE)
cttiR::update(sources = "public-reflow", mode = "remote", dry_run = TRUE)To store document text, a registration must also declare a reviewed
documentation_rights basis covering those documents.
Without it, the updater retains inventory and hashes only. Do not assume
a package license covers all third-party assets.
Remote GitHub mode resolves one commit and verifies bounded downloads against Git blob hashes. It does not install the source package. Local mode never fetches remote records. Discovery, pruning, non-GitHub backends and release migration remain pending. A failed selected source prevents activation.
Updates retain complete immutable snapshots. Existing projects keep
their pins; removed exports do not reappear through fallback to an older
bundled package. Use rollback_knowledge(id) to preview a
retained composite snapshot and dry_run = FALSE to apply
it. Initial resource observation times can make preview and applied
composite IDs differ even when API content is identical.
An applied update can recover a verified stopped local catalog writer after checking the active snapshot and activation journal. It retains old writer evidence. Live or unknown writers, conflicting journals and corrupt snapshots are refused. An interrupted recovery guard requires manual review.
Audit is local and read-only by default. It does not open referenced datasets or run an analysis. This example checks only the project:
A warning or untested readiness check is not scientific clearance.
strict = TRUE raises a typed condition for required
failures or required unverified checks. repair = TRUE uses
a restricted repair set: it does not overwrite arbitrary user edits.
Consult help("audit", package = "cttiR") before repair.
For new adapted-layout projects, run this from the generated project root only after installing the rendering dependencies explicitly and reviewing any page edits:
Rendering intentionally executes reviewed R Markdown chunks. The
bundled fixture uses synthetic values; it does not fit the project’s
study data. The adaptation records its pinned reflowR source and MIT
notice, while using rmarkdown::render_site explicitly. It
does not invoke reflow_init() or workflowr and does not
claim all upstream reproducibility features.
Base package evidence can come from an explicitly acquired, reviewed
R source tree. Register the distribution root and exact package name;
preview remains read-only. This never downloads, builds or installs R.
The package’s original DESCRIPTION.in stays unchanged,
while metadata substitutes the distribution version in memory. The
distribution VERSION and COPYING hashes
contribute to source identity. Documentation storage requires an
explicit rights basis.
options(cttiR.sources = list(list(
id = "reviewed-r-source", r_distribution = "/path/to/R-4.6.1",
package = "stats", documentation_rights = "Reviewed local storage rights"
)))
cttiR::update(sources = "reviewed-r-source", dry_run = TRUE)Newly indexed sources also retain S3 generic/class registrations and
the exact statically resolved implementation signature, including
non-exported methods. Search labels these as method declarations, never
as public exports or installed dispatch proof. Duplicate registrations
and unknown implementations remain unresolved. packages()
reports S3 counts; historical snapshots without this index report
missing counts rather than zero methods. Update differences report
removed registrations and changed implementation evidence
separately.
This indexes the package subtree, not all distribution manuals or NEWS. A local registration is not proof of canonical origin, installed numerical equivalence, complete documentation coverage or workflow approval. Development versions and ambiguous source locations are refused.
With shiny and callr installed,
setup_app() provides Fast/Detailed creation, and
configure(path) uses the same synchronization engine. It is
a local interface. Use Save or resume a draft to export
a JSON file or restore saved answers. Drafts contain user
text/configuration but exclude the parent directory, local bindings and
accepted preview. Restoring requires a fresh preview, and Configure
drafts must match the project identity. Review sensitive content before
sharing; drafts are not saved automatically. The full typed
questionnaire and remaining workflow views are still incomplete.
Runtime setup is explicit. The live-tested installer currently targets Linux x86_64 and verifies the pinned Ollama runtime and local model. Offline setup never acquires software or pulls a model. A successful inference probe is not a qualified workflow planner. No CRAN submission is performed by these functions.