--- title: "Create, inspect and maintain a research scaffold" output: rmarkdown::html_vignette: mathjax: null vignette: > %\VignetteIndexEntry{Create, inspect and maintain a research scaffold} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} resource_files: - figures/logo.svg - figures/logo-dark.svg --- ```{r setup, include=FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") # This vignette owns only this disposable example directory. example_root <- tempfile("cttir-vignette-") dir.create(example_root) old_catalog_option <- getOption("cttiR.catalog_dir") options(cttiR.catalog_dir = file.path(example_root, "catalog")) ``` 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. ## Start with three inputs `path` is the existing **parent** directory. Creation uses a portable child name. A preview does not create the child or install dependencies. ```{r preview} plan <- cttiR::project( "Example comparison", "methods", "Plan a reproducible tabular comparison", path = example_root, dry_run = TRUE ) plan$spec$project[c("name", "slug", "type")] plan$readiness stopifnot(!dir.exists(plan$path)) ``` Apply the same request explicitly: ```{r create} p <- cttiR::project( "Example comparison", "methods", "Plan a reproducible tabular comparison", path = example_root ) stopifnot(dir.exists(p$path)) p$spec$analysis ``` Creation 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. ## Repeat safely and inspect explicit changes 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. ```{r repeat} 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. ```{r sync} preview <- cttiR::sync(p$path, options = list(project = list(language = "de"))) preview$actions[preview$actions$action != "skip", c("path", "action")] stopifnot(preview$state == "planned") applied <- cttiR::sync( p$path, options = list(project = list(language = "de")), dry_run = FALSE ) applied$state ``` 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. ## Record analysis mappings without running a model 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: ```{r analysis-mapping} 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")] 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. ```{r model-settings} 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")] 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. ```{r explicit-data-check} 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")] 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. ## Query evidence without approving a workflow 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. ```{r evidence} hit <- cttiR::search("reflowR::reflow_init", path = p$path) hit[, c("package", "revision", "verification", "approved")] 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: ```{r coverage} known <- cttiR::packages(path = p$path) known[known$package == "reflowR", c("package", "documents_discovered", "documents_stored", "approved")] ``` `ask(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. ## Refresh only sources you select The following examples are deliberately not run by the vignette. They show explicit local and public GitHub source registration: ```{r update-examples, eval=FALSE} 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 and render intentionally Audit is local and read-only by default. It does not open referenced datasets or run an analysis. This example checks only the project: ```{r audit} report <- cttiR::audit(p$path, scope = "project") report$overall_status ``` 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: ```{r render-example, eval=FALSE} # In a terminal at the generated project root: # Rscript code/render_report.R ``` 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. ## Index a local R distribution source 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. ```{r distribution-source, eval=FALSE} 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. ## Optional local interface and runtime 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. ```{r optional-tools, eval=FALSE} cttiR::setup_app() cttiR::configure(p$path) cttiR::setup(dry_run = TRUE) ``` 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. ```{r cleanup, include=FALSE} options(cttiR.catalog_dir = old_catalog_option) unlink(example_root, recursive = TRUE) ```