Skip to contents

This developer article documents the supported drm_formula() grammar, including response blocks, distributional-parameter formulae, and validation rules. bf() remains a short alias. It assumes you have already written a first formula from a family tutorial and now need the complete grammar and status table, not another worked example.

The design reference is docs/design/01-formula-grammar.md.

Fixed-effect formulas use base R’s ordinary formula machinery. Transformations and interaction expansions such as poly(x1, 2), I(x1^2), x1 * x2, and (x1 + x2 + x3)^2 work for implemented fixed-effect distributional-parameter formulas. For ecological and evolutionary examples, second-order terms are usually the practical default; third-order polynomials should be treated as exceptional and justified by the question and data.

Current status map

Use this table before copying syntax into an analysis. “Implemented” means the syntax is parsed and has a fitted likelihood path for the family named in the notes. “Reserved” means the syntax is part of the public design vocabulary but should currently give a clear unsupported-feature error rather than a fit. “Planned” means the syntax is shown only to explain the roadmap.

In this table, “coscale” means a model for residual correlation, currently rho12 in two-response Gaussian models.

If the family itself is missing from this table, the gap is not a formula question – see Adding distribution families for how a new distribution enters the package.

Syntax Current status Notes
drm_formula() and bf() Implemented drm_formula() is the explicit constructor; bf() is a short alias.
y ~ x1 + x2, sigma ~ x1 Implemented Univariate Gaussian location-scale model.
y ~ x1 + x2, sigma ~ x1, nu ~ x2 Implemented Fixed-effect univariate Student-t location-scale-shape model.
y ~ x1 + (1 | id) + (0 + x1 | id), sigma ~ x2, nu ~ 1, family = student() Implemented first slice Ordinary Student-t mu random intercepts and independent numeric slopes enter the identity-location predictor. A single unlabelled spatial(1 + x | id, coords = coords) one-slope structured effect on mu is recovery grade – trust the point estimate, not the interval. The intercept-only spatial mu route and exact nu ~ phylo(1 | id, tree = tree) structured-intercept route are diagnostic grade only. Correlated slopes, labelled covariance blocks, sigma random effects, other nu random effects, other structured providers (animal()/relmat() on mu; spatial()/animal()/relmat() on nu), additional structured slopes and labelled q2/q4 blocks, known covariance, and bivariate Student-t models remain planned.
y ~ x1 + (1 | id) + (0 + x1 | id), sigma ~ x2, nu ~ x3, family = skew_normal() Implemented first slice Skew-normal ordinary mu random intercepts and independent numeric slopes enter the response-mean predictor. The exact independent-slope ledger cell is inference-ready with caveats for true SD 0.50 and M>=16. Public sigma is response SD and nu is residual slant. Correlated or labelled slopes, random effects outside mu, structured effects, bivariate routes, and broader calibration remain planned.
y ~ x1 + x2, sigma ~ x1, family = lognormal() Implemented Fixed-effect univariate lognormal model for positive responses; mu and sigma are on the log-response scale.
y ~ x1 + (1 | id) + (0 + x1 | id), sigma ~ x2, family = lognormal() Implemented first slice Ordinary lognormal mu random intercepts and independent numeric slopes enter the log-response location. Arc 3a also admits recovery-grade unlabelled q1 phylo(1 | id, tree = tree) and relmat(1 | id, K/Q = ...) intercepts in mu. Correlated or labelled slopes, other structured effects, known covariance, and bivariate lognormal models remain planned.
y ~ x1, sigma ~ x2 + (1 | id), family = lognormal() Implemented first slice An ordinary lognormal sigma random intercept enters log-sigma; only its exact ledger domain is inference-ready with caveats. This scale route cannot be combined with a mu random effect, and sigma slopes or labels remain unsupported.
y ~ x1 + x2, sigma ~ x1, family = Gamma(link = "log") Implemented Fixed-effect univariate Gamma mean-CV model for positive responses; mu is the response mean and sigma is the coefficient of variation.
y ~ x1 + (1 | id) + (0 + x1 | id), sigma ~ x2, family = Gamma(link = "log") Implemented first slice Ordinary Gamma mu random intercepts and independent numeric slopes enter the log-mean predictor. A single unlabelled relmat(1 | id, K = K) or relmat(1 + x | id, K = K) structured intercept or one-slope on mu is implemented at recovery grade. Arc 3a also admits a recovery-grade unlabelled q1 phylo(1 | id, tree = tree) intercept. Correlated or labelled slopes, new-route slopes, other structured providers (spatial()/animal()), known covariance, and bivariate or mixed Gamma models remain planned.
y ~ x1, sigma ~ x2 + (1 | id), family = Gamma(link = "log") Implemented first slice An ordinary Gamma sigma random intercept enters log-CV. Its ML-Laplace profile interval is inference-ready with caveats only at true SD 0.40, n_each=12, and M >= 32 (M=16 borderline). This scale route cannot be combined with a mu random effect; sigma slopes, labels, REML, and supported remain outside the claim.
y ~ x1 + x2 + (1 | id) + (0 + x1 | id), sigma ~ x1, nu ~ 1, family = tweedie() Implemented first slice Tweedie model for non-negative semicontinuous responses with exact zeros; ordinary mu random intercepts and independent numeric slopes are fitted. The exact independent-slope ledger cell is inference-ready with caveats for true SD 0.50 and M>=16. Public sigma maps to phi = sigma^2, and nu is constrained to 1 < nu < 2. Predictor-dependent nu, distributional random effects beyond ordinary mu, structured effects, zero-inflation aliases, and hurdle aliases remain planned.
y ~ x1 + x2, sigma ~ x1, family = beta() Implemented Fixed-effect beta mean-scale model for strict continuous proportions in (0, 1); public sigma maps internally to phi = 1 / sigma^2.
y ~ x1 + (1 | id) + (0 + x1 | id), sigma ~ x2, family = beta() Implemented first slice Ordinary beta mu random intercepts and independent numeric slopes enter the logit-mean predictor for strict (0, 1) responses. Row-specific structured exceptions are the recovery-grade animal() routes and the exact unlabelled q1 phylo(1 | species, tree = tree) intercept in mu documented below; family sigma remains fixed-effect-only for the phylogenetic cell. Correlated slopes, labelled covariance blocks, ordinary sigma random effects, exact 0/1 boundary mass, zoi/coi, spatial()/relmat(), phylogenetic slopes or scale-side structure, labelled q2/q4 or joint mu+sigma structured blocks, known covariance, beta-binomial denominators, and bivariate or mixed bounded-response models remain planned.
y ~ x1 + (1 | id) + (0 + x1 | id), sigma ~ x2, zoi ~ x3, coi ~ x4, family = zero_one_beta() Implemented first slice Zero-one beta model for continuous proportions on [0, 1] with exact structural boundary mass and ordinary mu random intercepts or independent numeric slopes. The exact independent-slope ledger cell is inference-ready with caveats for true SD 0.50 and M>=16 under its generator-qualified evidence; it does not establish a general boundary-mass calibration claim. mu and sigma describe the interior beta component, zoi is exact-boundary probability, coi is the probability of an exact one conditional on the boundary, and fitted() includes boundary mass. Random effects in sigma, zoi, or coi, correlated or labelled covariance, structured effects, denominators, and bivariate or mixed bounded-response models remain planned.
y01 ~ x1 + x2 + (1 | id) + (0 + x1 | id), family = stats::binomial(link = "logit") Implemented first slice Plain Bernoulli response model for explicit 0/1 event data. mu is the event probability and there is no public sigma; ordinary mu random intercepts and independent numeric slopes are fitted. Only the exact ledger domain for the independent slope is inference-ready with caveats. Non-logit links, factor responses, proportions with trial weights, correlated or labelled slopes, structured effects, bivariate responses, and the halted engine = "julia" bridge remain unavailable; Julia support is future work.
cbind(success, failure) ~ x1 + x2 + (1 | id) + (0 + x1 | id), family = stats::binomial(link = "logit") Implemented first slice Plain binomial response model for counted events out of known trials, with trials = success + failure, fixed effects plus ordinary mu random intercepts and independent slopes, and ordinary binomial sampling variation. Use beta_binomial() instead when extra-binomial variation is part of the scientific model.
cbind(success, failure) ~ x1 + (1 | id) + (0 + x1 | id), sigma ~ x2, family = beta_binomial() Implemented first slice Ordinary beta-binomial mu random intercepts and independent numeric slopes enter the logit success-probability predictor for counted successes out of known trials. Correlated slopes, labelled covariance blocks, sigma random effects, zoi/coi, structured effects, known covariance, and bivariate or mixed bounded-response models remain planned.
y ~ x1 + x2, family = poisson(link = "log") Implemented Fixed-effect univariate Poisson mean model for non-negative integer counts.
y ~ x1 + (1 | id) + (0 + x1 | id), family = poisson(link = "log") Implemented first slice Ordinary Poisson mu random intercepts and independent numeric slopes on the log-mean scale. Correlated Poisson slope blocks, labelled covariance blocks, zero-inflated Poisson random effects beyond the exact diagnostic-only q=1 zi ~ spatial(1 | id, coords = coords) intercept, and cross-parameter covariance remain planned.
y ~ x1 + offset(log(exposure)), family = poisson(link = "log") Implemented Exposure/rate Poisson model using standard R offset() syntax in the mu formula.
y ~ x1 + x2, zi ~ x1, family = poisson(link = "log") Implemented Fixed-effect zero-inflated Poisson model; mu is the conditional count mean and zi is the structural-zero probability.
y ~ x1 + x2, sigma ~ x1, family = nbinom2() Implemented Fixed-effect univariate negative-binomial 2 model for overdispersed counts; sigma is an overdispersion scale.
y ~ x1 + (1 | id) + (0 + x1 | id), sigma ~ x2, family = nbinom2() Implemented first slice Ordinary NB2 mu random intercepts and independent numeric slopes on the log-mean scale. Correlated NB2 slope blocks, labelled covariance blocks, zero-inflated NB2 random effects outside the exact fixed-zi spatial structured-mu local-fit gate, and joint mu/sigma random effects remain planned.
y ~ x1, sigma ~ x2 + (1 | id), family = nbinom2() Implemented first slice Ordinary NB2 grouped overdispersion random intercepts on the log-sigma scale. Exact q1 structured sigma intercept-plus-one-slope routes for phylo(), spatial(), animal(), and relmat() are also fitted at recovery grade. Ordinary NB2 sigma slopes, labelled covariance blocks, joint mu/sigma random effects, zero-inflated/truncated/hurdle scale random effects, richer structured sigma blocks, and structured-sigma intervals/coverage remain planned.
y ~ x1 + offset(log(exposure)), sigma ~ x2, family = nbinom2() Implemented Exposure/rate NB2 model; the offset enters the mu linear predictor and sigma remains overdispersion.
y ~ x1 + x2, sigma ~ x1, zi ~ x2, family = nbinom2() Implemented Fixed-effect zero-inflated NB2 model; mu and sigma describe the conditional count component and zi is structural-zero probability.
y ~ x1 + spatial(1 | site, coords = coords), sigma ~ 1, zi ~ 1, family = nbinom2() Implemented diagnostic-only gate Row-specific Q-Series v1.0 fit/extractor evidence for fixed-covariance spatial structured mu with fixed zero inflation. It exposes sdpars$mu, ranef("spatial_mu"), and a direct profile_targets() row, but it does not establish point-estimate recovery; intervals, coverage, inference_ready, supported, labelled q2/q4 count covariance, zero-inflated NB2 structured zi, structured sigma, REML, AI-REML, and bridge support remain unavailable.
y ~ x1 + x2, sigma ~ x1, family = truncated_nbinom2() Implemented Fixed-effect zero-truncated NB2 model for positive counts; mu and sigma describe the untruncated count component and fitted() is the positive-count mean.
y ~ x1 + (1 | id) + (0 + x1 | id), sigma ~ x2, family = truncated_nbinom2() Implemented first slice Ordinary zero-truncated NB2 mu random intercepts and independent numeric slopes enter the log-mean predictor while sigma remains fixed-effect overdispersion. One exact q1 hu ~ relmat(K/Q) intercept is diagnostic-only when the hurdle route is active; ordinary count-side mu random effects then remain blocked. Correlated slopes, labelled covariance blocks, hurdle-side random effects beyond that exact gate, sigma random effects, structured effects on mu/sigma, and bivariate count models remain planned.
y ~ x1 + x2, sigma ~ x1, hu ~ x2, family = truncated_nbinom2() Implemented Fixed-effect hurdle NB2 model; hu is the hurdle-zero probability and nonzero counts come from the zero-truncated NB2 component. A single unlabelled hu ~ relmat(1 | id, K = K) or hu ~ relmat(1 | id, Q = Q) q=1 structured intercept on the hurdle side is also implemented as diagnostic-only (local-fit only; no coverage or intervals), inherited by the hurdle_nbinom2 alias. Structured phylo()/spatial()/animal(), structured slopes, labelled q2/q4 blocks, and structured mu/sigma remain planned.
(1 | id) in mu Implemented Ordinary Gaussian location random intercept.
(0 + x1 | id) in mu Implemented Independent numeric location random slope.
(1 + x1 | id) in mu Implemented Correlated ordinary intercept-slope block.
(1 + x1 | p | id) in mu Implemented for naming p labels the group-level covariance block for output and future matching.
(1 | id) in sigma Implemented Residual-scale random intercept in the univariate Gaussian sigma formula.
(1 | p | id) in both mu and sigma Implemented First univariate location-scale covariance slice; p labels one mean-scale random-intercept covariance block.
sd(id) ~ x_group Implemented Models the SD of an unlabelled Gaussian mu random intercept; predictors must be group-level.
meta_V(V = V) Implemented Preferred spelling for known diagonal, block-diagonal, or dense sampling covariance in a Gaussian model; bivariate Gaussian known V uses a complete-row 2n by 2n row-paired matrix.
meta_known_V(V = V) Deprecated compatibility alias Warns and then uses the same additive known-covariance path. New code should use meta_V(V = V).
mu1, mu2, sigma1, sigma2, rho12 Implemented for fixed effects Bivariate Gaussian location-coscale model with predictor-dependent residual correlation.
(1 | p | id) in both bivariate mu1 and mu2 Implemented First bivariate group-level covariance slice; p labels a mu1/mu2 random-intercept covariance block.
(1 | p | id) in both bivariate sigma1 and sigma2 Implemented First bivariate residual-scale covariance slice; p labels a sigma1/sigma2 random-intercept covariance block on the log-sigma scale.
(0 + x | p | id) in both bivariate sigma1 and sigma2 Implemented first slice p labels a sigma1/sigma2 scale-slope block on the log-sigma scale, reported as cor(sigma1:x,sigma2:x | p | id).
(0 + x | p | id) in same-response bivariate mu1 and sigma1, or mu2 and sigma2 Implemented first slice Matching slope-only terms create one response-specific mean-scale-slope covariance row, such as cor(mu1:x,sigma1:x | p | id). Cross-response slope labels remain planned.
(1 | p | id) in same-response bivariate mu1 and sigma1, with optional independent (1 | q | id) in mu2 and sigma2 Implemented first slice Each labelled random-intercept pair creates its own response-specific mean-scale covariance block; residual rho12 stays separate.
(1 | p | id) in all four bivariate mu1, mu2, sigma1, and sigma2 formulas Implemented first slice One ordinary q=4 location-scale covariance block reports all six latent random-effect correlations.
(1 + x | p | id) in all four bivariate mu1, mu2, sigma1, and sigma2 formulas Implemented first diagnostic slice One ordinary q8 endpoint block estimates eight endpoint SDs and reports 28 derived latent correlations. The Phase 18 smoke/recovery artifact lane reports bias, RMSE, MCSE, and interval unavailability; it is not coverage or power evidence.
sd1(id) ~ x_group, sd2(id) ~ x_group Implemented Family B direct SD formulas for labelled bivariate location random intercepts; not for residual-scale random effects.
family = c(gaussian(), gaussian()) Implemented Routes to the bivariate Gaussian engine; mixed composed families are planned.
biv_gaussian() Implemented legacy helper Kept for compatibility while composed families become the public direction.
mvbind(y1, y2) ~ x1 Implemented Shorthand for identical bivariate location formulas; explicit mu1/mu2 remains preferred for different predictors.
phylo(1 | species, tree = tree) in mu and/or sigma Implemented Intercept-only univariate Gaussian phylogenetic location and residual-scale effect; matching mu/sigma terms estimate one latent structured correlation. Requires an ultrametric tree with branch lengths.
y ~ x + phylo(1 | species, tree = tree), sigma ~ z, family = beta() Implemented exact q1 recovery slice One unlabelled intercept-only phylogenetic location effect in Beta mu; family sigma remains fixed-effect-only and controls phi = sigma^(-2). Point recovery passed only in the exact tested g = 1024, m = 4 regime. This is not g >= 1024; slopes, labels/q2+, phylogeny in family sigma, direct latent-sd() regression, REML, intervals, and coverage remain deferred.
animal(1 | id, pedigree = pedigree), animal(1 | id, A = A), or animal(1 | id, Ainv = Ainv) in mu and/or sigma Implemented first slice Univariate Gaussian animal-model random intercept from a dense pedigree-derived additive relationship matrix, precomputed additive relatedness, or inverse-relatedness matrix. Matching mu/sigma terms estimate one latent structured correlation. One numeric mu slope is fitted; the exact A-matrix q1 sigma one-slope route is also fitted and inference-ready with caveats under raw log-SD Wald-z intervals. Pedigree/Ainv bridge marshalling, sparse large-pedigree construction, additional multiple or labelled structured-slope layouts outside the exact fitted ledger cells, structured slope correlations, predictor-dependent corpair(), and direct-SD grammar remain planned.
matching labelled animal(1 | p | id, pedigree = pedigree), animal(1 | p | id, A = A), or animal(1 | p | id, Ainv = Ainv) in bivariate mu1 and mu2 Implemented first q=2 slice Estimates two latent animal-model location scales and one animal mean-mean correlation from the same pedigree-derived or precomputed matrix. Individual marginal SDs also include sqrt(A[i, i]).
matching labelled animal(1 | p | id, pedigree = pedigree), animal(1 | p | id, A = A), or animal(1 | p | id, Ainv = Ainv) in all four bivariate mu1, mu2, sigma1, and sigma2 formulas Implemented first q=4 slice Estimates four latent animal-model endpoint scales and six constant latent location-location, location-scale, and scale-scale correlations from the same matrix. Individual marginal SDs also include sqrt(A[i, i]).
relmat(1 | id, K = K) or relmat(1 | id, Q = Q) in mu and/or sigma Implemented first slice Lower-level univariate Gaussian random intercept from a user-supplied latent relatedness covariance or precision matrix. Matching mu/sigma terms estimate one latent structured correlation. Keep observation-level known sampling covariance in meta_V(V = V).
matching labelled relmat(1 | p | id, K = K) or relmat(1 | p | id, Q = Q) in bivariate mu1 and mu2 Implemented first q=2 ML slice; exact supplied-K intercept-only REML cell at point_fit_recovery Estimates two latent relatedness location scales and one mean-mean correlation from the same user-supplied matrix. Native REML = TRUE requires biv_gaussian(), the identical named K, group ordering, and label in both location formulas, intercept-only sigma1, sigma2, and rho12, complete pairs, unit weights, and no other random, scale-side, meta_V(), direct-SD, or corpair() layer. Q, slopes, q4+, intervals, and coverage remain outside this REML cell. Level-specific marginal SDs also include the known diagonal multiplier.
matching labelled relmat(1 | p | id, K = K) or relmat(1 | p | id, Q = Q) in all four bivariate mu1, mu2, sigma1, and sigma2 formulas Implemented first q=4 slice Estimates four latent relatedness endpoint scales and six constant latent location-location, location-scale, and scale-scale correlations from the same matrix. Level-specific marginal SDs also include the known diagonal multiplier.
matching phylo(1 | species, tree = tree) in bivariate mu1 and mu2 Implemented first slice Estimates two phylogenetic location SDs and one phylogenetic mean-mean correlation.
labelled phylo(1 | p | species, tree = tree) in matching bivariate mu1 and mu2 Implemented The label is preserved in SD, correlation, corpairs(), and profile-target names for the phylogenetic mean-mean path.
labelled phylo(1 | p | species, tree = tree) in all four bivariate mu1, mu2, sigma1, and sigma2 formulas Implemented first slice One constant q=4 phylogenetic location-scale block estimates four endpoint SDs and six latent phylogenetic correlations. Partial, unlabelled, mismatched, and slope forms remain rejected.
count ~ x + phylo(1 | species, tree = tree) or count ~ x + spatial(1 | site, coords = coords), family = poisson(link = "log") Implemented first slice Ordinary non-zero-inflated Poisson q=1 structured mu intercept on the log-mean scale for one of phylo(), spatial(), animal(), or relmat(); unlabelled intercept-plus-one-slope terms are also fitted for those four providers. Pure, labelled, or multiple structured count slopes, q=2/q=4 count blocks, zero-inflated structured effects outside exact row-specific local-fit gates, simultaneous structured types within Poisson, and combinations with ordinary count random effects remain planned.
count ~ x + phylo(1 | species, tree = tree) or count ~ x + relmat(1 | id, Q = Q), sigma ~ z, family = nbinom2() Implemented first slice Ordinary non-zero-inflated NB2 q=1 structured mu intercept on the log-mean scale for one of phylo(), spatial(), animal(), or relmat(), while sigma remains fixed-effect overdispersion unless using a separate fitted sigma route; unlabelled intercept-plus-one-slope mu terms are also fitted for those four providers. Exact q1 structured sigma intercept-plus-one-slope routes for those four providers are recovery grade. One exact crossed mu ~ spatial(1 | site, coords = coords) + relmat(1 | id, Q = Q) route is recovery-only. Pure, labelled, or multiple structured count slopes, labelled q=2/q=4 count blocks, zero-inflated NB2 structure outside the exact local-fit gate, richer or labelled structured sigma, structured-sigma intervals/coverage, simultaneous structured types beyond that exact crossed gate, and joint mu/sigma random effects remain planned.
count ~ x + phylo_interaction(1 | partner1:partner2, tree1 = tree1, tree2 = tree2) or Gaussian y ~ x + phylo_interaction(...) Implemented first slice Single q=1 location random intercept for a two-partner phylogenetic interaction in univariate Gaussian mu and ordinary Poisson/NB2 mu. Internally this builds a sparse Kronecker precision from the two augmented phylogenetic precisions. relmat(1 | pair, Q = Q_pair) remains the lower-level escape hatch. Binary/Bernoulli incidence models and additive models that combine partner main phylogenies plus phylo_interaction() remain planned.
y ~ x1 + x2 + (1 | id) + (0 + x1 | id), family = cumulative_logit() Implemented first slice Univariate ordinal model for ordered scores with cutpoints; ordinary mu random intercepts and independent numeric slopes are fitted, and the exact mc-0227 slope cell is inference-ready with caveats under its recorded M>=80 design. A single unlabelled phylo(1 | species, tree = tree) structured mu intercept is diagnostic-only (fit/extractor feasibility, not point-estimate recovery or coverage). Correlated or labelled slopes, other structured routes (spatial()/animal()/relmat()), and scale/discrimination formulas are planned.
cbind(successes, failures) ~ x1, family = beta_binomial() Implemented Fixed-effect denominator-aware model for success counts with known trial totals; sigma is extra-binomial variation.
phylo(1 + x1 | species, tree = tree) Implemented first one-slope slice Univariate Gaussian mu path with independent phylogenetic intercept and slope fields; ordinary Poisson and NB2 also fit one unlabelled q1 intercept-plus-one-slope phylogenetic mu route at recovery/source-test grade. Pure, multiple, or labelled count slopes and labelled structured slope blocks such as phylo(1 + x | p | species, tree = tree) remain rejected until their covariance and recovery contracts are designed.
animal(1 + x | id, pedigree = ped) Implemented first one-slope slice Univariate Gaussian mu path with independent animal-model intercept and slope fields; additional multiple-slope layouts and slope correlations remain planned outside the exact fitted bivariate ledger cells. A labelled block in this univariate q1 route is rejected; use only the exact labelled bivariate layouts recorded as fitted in the ledger.
spatial(1 | site, coords = coords) Implemented first slice Univariate Gaussian mu spatial random intercept using a fixed coordinate covariance foundation; mesh/SPDE paths remain planned.
spatial(1 + x | site, coords = coords) Implemented first one-slope slice Univariate Gaussian mu spatial random intercept plus one numeric spatial slope. The two coordinate fields are independent and have separate SDs. A labelled block in this univariate q1 route is rejected; use only the exact labelled bivariate layouts recorded as fitted in the ledger.
spatial(1 | p | site, coords = coords) in matching bivariate mu1 and mu2 formulas Implemented q=2 slice; exact intercept-only native REML cell at point_fit_recovery Bivariate Gaussian location covariance for two coordinate-spatial random intercept fields. corpairs(level = "spatial") reports the spatial mean-mean row separately from residual rho12. Native REML = TRUE requires matching labels; intercept-only sigma1, sigma2, and rho12; complete response pairs; unit weights; no known meta_V() covariance; and no additional ordinary random, direct-SD, or corpair() layer. Slopes, range estimation, intervals, and coverage remain planned.
spatial(1 | p | site, coords = coords) in all four bivariate mu1, mu2, sigma1, and sigma2 formulas Implemented first q=4 slice One constant coordinate-spatial location-scale block estimates four endpoint SDs and six latent spatial correlations. Partial, unlabelled, mismatched, and slope forms remain rejected.
relmat(1 + x | id, K = K) Implemented first one-slope slice Univariate Gaussian mu path with independent lower-level relatedness intercept and slope fields; additional multiple-slope layouts and slope correlations remain planned outside the exact fitted bivariate ledger cells. A labelled block in this univariate q1 route is rejected; use only the exact labelled bivariate layouts recorded as fitted in the ledger.
corpair(id, level = "group", block = "p", from = "mu1", to = "mu2") ~ x_group Implemented Predictor-dependent ordinary q=2 location-location latent random-effect correlation regression for matching labelled mu1/mu2 random intercepts. Predictors must be constant within id.
corpair(species, level = "phylogenetic", block = "p", from = "mu1", to = "mu2") ~ ecology Implemented Predictor-dependent phylogenetic q=2 location-location latent random-effect correlation regression for matching labelled mu1/mu2 phylo() terms. Predictors must be constant within species. Location-scale, scale-scale, q=4, and spatial corpair() regressions remain planned.
Matching slope-only (0 + x | p | id) in bivariate mu1 and mu2 Implemented first bivariate slope slice Estimates the ordinary slope1-slope2 plasticity-syndrome correlation without intercept-slope correlations; broader bivariate slope blocks remain planned.
Matching one-slope intercept-plus-slope (1 + x | p | id) blocks in bivariate mu1 and mu2 Implemented first q=4 location slice Estimates two location-intercept SDs, two location-slope SDs, and six group-level latent correlations; the SDs are direct profile targets and the correlations are derived-unavailable interval rows.
Matching two-slope (1 + x + z | p | id) blocks in bivariate mu1 and mu2 Implemented q=6 location slice with smoke artifact routing Estimates six location SDs and 15 group-level latent correlations; the SDs are direct profile targets and the correlations are derived-unavailable interval rows.
p8 endpoint blocks, q8 variants beyond the first matching all-four ordinary endpoint slice, labelled or cross-formula residual-scale slope blocks, broader bivariate residual-scale blocks beyond the matching q2 sigma1/sigma2 scale-slope slice, non-Gaussian cross-parameter covariance, predictor-dependent q=4 phylogenetic/spatial correlations, or rho12 random effects Planned These need a larger covariance parameterization, simulation, and naming checks before fitting. Unlabelled ordinary univariate correlated sigma blocks are already fitted. Intercept-slope corpair() rows are distant-future; broader slope-correlation regressions need coefficient-aware syntax.
corpairs(fit) Implemented for current fitted correlations Reports residual rho12, ordinary and bivariate group-level covariance rows including ordinary q=4 blocks, bivariate phylogenetic mean-mean or q=4 rows, bivariate coordinate-spatial q=2 or constant q=4 rows, and the animal/relmat() q=2 or constant q=4 rows.

Current implemented univariate Gaussian random-effect forms include:

drm_formula(y ~ x + (1 | id), sigma ~ z)
drm_formula(y ~ x + (0 + x | id), sigma ~ z)
drm_formula(y ~ x + (1 + x | id), sigma ~ z)
drm_formula(y ~ x + (1 + x | p | id), sigma ~ z)
drm_formula(y ~ x + (1 | id), sigma ~ z + (1 | id) + (0 + w | id))
drm_formula(y ~ x, sigma ~ z + (1 + w | id))
drm_formula(y ~ x + (1 | p | id), sigma ~ z + (1 | p | id))
drm_formula(y ~ x + (1 | id), sigma ~ z, sd(id) ~ x_group)
drm_formula(y ~ x + phylo(1 | species, tree = tree), sigma ~ z)
drm_formula(y ~ x + animal(1 | id, Ainv = Ainv), sigma ~ z)
drm_formula(y ~ x + relmat(1 | line, Q = Q), sigma ~ z)
drm_formula(
  y ~ x + (1 | id) + (1 | site),
  sigma ~ z,
  sd(id) ~ x_group,
  sd(site) ~ site_type
)

Current implemented Student-t form:

drm_formula(y ~ x, sigma ~ z, nu ~ 1)
drm_formula(y ~ x, sigma ~ z, nu ~ x)
drm_formula(y ~ x + (1 | id) + (0 + x | id), sigma ~ z, nu ~ 1)

Student-t ordinary mu random intercepts and independent numeric slopes are a first location slice, joined by a spatial(1 | id, coords = coords) structured mu intercept (diagnostic grade only; it confirms fit/extractor feasibility but does not establish point-estimate recovery) and a phylo(1 | id, tree = tree) structured nu intercept (diagnostic grade only). Correlated Student-t slopes, sigma random effects, other nu random effects, known sampling covariance, other structured providers on mu/nu, and bivariate Student-t models are later phases.

Future skew-normal and skew-t formulas should also start with fixed-effect residual-shape terms such as nu ~ x. A later latent-effect spelling such as skew(id) ~ x_group would ask a different question about the distribution of group effects and should not be taught as an alias for residual nu.

Current implemented lognormal form:

drm_formula(biomass ~ habitat, sigma ~ treatment)

paired with:

family = lognormal()

The response must be positive and finite. mu and sigma are defined on the log-response scale, and fitted() returns the arithmetic response mean exp(mu + sigma^2 / 2).

Current implemented Gamma form:

drm_formula(biomass ~ habitat, sigma ~ treatment)

paired with:

family = Gamma(link = "log")

Here mu is the response mean and sigma is the coefficient of variation. Gamma mu random intercepts and independent numeric slopes are an implemented first slice at recovery grade. A separate ordinary sigma random intercept is also fitted at recovery grade; it cannot be combined with a mu random effect. A single unlabelled relmat(1 | id, K = K) intercept or one-slope structured effect on mu is fitted at recovery grade. Correlated or labelled slopes, sigma slopes, known sampling covariance, phylo()/spatial()/animal() structured terms, and bivariate or mixed Gamma models are later phases.

The middle p is a group-level covariance-block label. It is not residual rho12, and reserved distributional parameter names such as rho12 should not be used as labels. Matching (1 | p | id) terms in univariate Gaussian mu and sigma fit the first mean-scale covariance block; larger cross-formula blocks with slopes remain future work.

Current implemented bivariate form:

drm_formula(
  mu1 = y1 ~ x1 + x2,
  mu2 = y2 ~ x1,
  sigma1 = ~ x1 + x2,
  sigma2 = ~ x1,
  rho12 = ~ x1 + x2
)

When both responses share the same location predictors, the shorter form is also implemented:

drm_formula(
  mvbind(y1, y2) ~ x1 + x2,
  sigma1 = ~ x1 + x2,
  sigma2 = ~ x1,
  rho12 = ~ x1 + x2
)

This expands internally to mu1 = y1 ~ x1 + x2 and mu2 = y2 ~ x1 + x2. Use the explicit mu1 and mu2 formulas when the two responses need different location predictors.

The first fitted structured-effect marker examples are phylogenetic location effects:

drm_formula(y ~ x + phylo(1 | species, tree = tree), sigma ~ z)
drm_formula(y ~ x + phylo(1 + x | species, tree = tree), sigma ~ z)

phylo() uses an ultrametric branch-length tree and adds tree-structured Gaussian random intercept and one-slope fields to the mu predictor. Matching intercept-only phylo() terms in bivariate mu1 and mu2 formulas fit the first phylogenetic mean-mean correlation slice:

drm_formula(
  mu1 = y1 ~ x + phylo(1 | species, tree = tree),
  mu2 = y2 ~ x + phylo(1 | species, tree = tree),
  sigma1 = ~ 1,
  sigma2 = ~ 1,
  rho12 = ~ 1
)

Matching labelled phylo() terms across all four bivariate Gaussian endpoints fit the constant q=4 phylogenetic location-scale block. A single shared label estimates one full q4 tree block; using one label for mu1/mu2 and another for sigma1/sigma2 estimates the block-diagonal fallback:

drm_formula(
  mu1 = y1 ~ x + phylo(1 | pl | species, tree = tree),
  mu2 = y2 ~ x + phylo(1 | pl | species, tree = tree),
  sigma1 = ~ z + phylo(1 | ps | species, tree = tree),
  sigma2 = ~ z + phylo(1 | ps | species, tree = tree),
  rho12 = ~ 1
)

Additional multiple or labelled phylogenetic-slope layouts outside the exact fitted ledger cells, richer residual-scale structured slopes beyond the exact q1 routes, partial or mismatched bivariate phylogenetic scale terms, structured effects in rho12, multiple animal-model slopes, multiple lower-level relmat() slopes, multiple spatial slopes, and mesh-based spatial terms are still planned:

# planned; drmTMB() will currently reject these
drm_formula(y ~ x + phylo(1 + x1 + x2 | species, tree = tree), sigma ~ z)
drm_formula(y ~ x + phylo(1 + x | p | species, tree = tree), sigma ~ z)
drm_formula(y ~ x + animal(1 + x1 + x2 | id, pedigree = ped), sigma ~ z)
drm_formula(y ~ x + animal(1 + x | p | id, pedigree = ped), sigma ~ z)
drm_formula(y ~ x + relmat(1 + x1 + x2 | id, K = K), sigma ~ z)
drm_formula(y ~ x + relmat(1 + x | p | id, K = K), sigma ~ z)
drm_formula(y ~ x + spatial(1 + x | p | site, coords = coords), sigma ~ z)
drm_formula(y ~ x + spatial(1 | site, mesh = mesh), sigma ~ z)

The first fitted spatial() paths use coordinates directly for univariate Gaussian mu coefficient fields:

drmTMB(
  bf(y ~ x + spatial(1 | site, coords = coords), sigma ~ z),
  family = gaussian(),
  data = dat
)

drmTMB(
  bf(y ~ x + spatial(1 + x | site, coords = coords), sigma ~ z),
  family = gaussian(),
  data = dat
)

coords can have one row per site or one row per observation, but coordinates must be constant within each site. A precomputed mesh remains planned. Mesh is not the scientific sampling level. It is the computational scaffold that will keep a future SPDE/GMRF spatial field scalable. These structured effects are separate from residual rho12.

For structured slopes, the fitted coordinate-spatial path now supports one numeric mu slope as independent intercept and slope fields with separate SDs. Additional structured slopes remain the advanced path after more recovery evidence. Multiple random factors should remain separate additive blocks. The first slope models should not estimate predictor-dependent intercept-slope corpair() rows. The first fitted bivariate targets are the slope1-slope2 correlation and the q4/q6 location blocks with smoke artifact routing for the same covariates across responses.

The first bivariate group-level covariance syntax is explicit about the distinction between group-level covariance labels and residual rho12:

drm_formula(
  mu1 = y1 ~ x1 + x2 + (1 | p | ID),
  mu2 = y2 ~ x1      + (1 | p | ID),
  sigma1 = ~ x1 + x2 + (1 | q | ID),
  sigma2 = ~ x1      + (1 | q | ID),
  rho12 = ~ x1 + x2
)

The shared p label fits a group-level random-intercept covariance block for the two response means. The shared q label fits a separate scale-scale block for the two residual-scale random intercepts on the log-sigma scale. The same-response mean-scale bridge is also implemented for one or both responses: a shared label in mu1 and sigma1 gives a response-1 mean-scale row, while a different shared label in mu2 and sigma2 gives a separate response-2 mean-scale row. Reusing the same label and group in all four bivariate formulas fits the first ordinary q=4 location-scale block:

drm_formula(
  mu1 = y1 ~ x + (1 | p | ID),
  mu2 = y2 ~ x + (1 | p | ID),
  sigma1 = ~ z + (1 | p | ID),
  sigma2 = ~ z + (1 | p | ID),
  rho12 = ~ w
)

That q=4 block reports one location-location row, four location-scale rows, and one scale-scale row in corpairs(). Fitted rows still use the older mean-mean and mean-scale class names, but corpairs() accepts location-location and location-scale as filter aliases to match the reserved corpair() formula wording. The first fitted corpair() route is the ordinary q=2 location-location model: corpair(ID, level = "group", block = "p", from = "mu1", to = "mu2") ~ w. The predictor w must be constant within ID, and corpairs() reports the mean, range, and number of fitted group-level correlations. Later location-scale routes should also be endpoint-specific, for example corpair(ID, level = "group", block = "p", from = "mu1", to = "sigma2") ~ w, because the four location-scale pairs in q=4 models do not have identical interpretation. For phylogenetic life-history trade-off models, the same grammar now also covers the fitted q=2 location-location route: corpair(species, level = "phylogenetic", block = "p", from = "mu1", to = "mu2") ~ ecology. The phylogenetic formula has an extra design gate: because the tree couples all species, drmTMB needs a positive-definite covariance contract for the full species block before a species-level predictor can change the latent phylogenetic correlation. The selected q=2 contract uses two independent unit phylogenetic fields and species-specific loadings, so variable rho_l is a nonstationary phylogenetic covariance model rather than a residual-style correlation row. It covers mu1-mu2 only; phylogenetic location-scale and scale-scale correlation regressions remain q=4 extensions. Multiple-slope bivariate location blocks beyond the smoke-routed ordinary q4/q6 lanes, bivariate spatial slope blocks, predictor-dependent q=4 phylogenetic or spatial correlations, p8 endpoint slope covariance, q8 variants beyond the first ordinary diagnostic lane, and rho12 random effects remain planned. Double-hierarchical bivariate fits should continue to report correlation pairs in a long table, not just as unlabeled matrices. The design note docs/design/20-coscale-correlation-pairs.md records the planned labels: correlation level, group, covariance block, distributional parameters, responses, and random-effect coefficients. The current corpairs(fit) helper already uses this table shape for residual rho12, ordinary univariate Gaussian mu random-effect correlations, and the implemented bivariate mean-mean, scale-scale, response-specific mean-scale, ordinary q=4, and phylogenetic mean-mean and q=4 random-intercept correlations.