---
title: "Backend Reliability, Parity and Object Schemas"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Backend Reliability, Parity and Object Schemas}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(gp3bayes)
```

## Two interchangeable implementation backends, one modeling contract

The approved full-MCMC interface remains `brms` with either `rstan` or
`cmdstanr`. Backend portability should preserve the model family, formula,
priors, estimand and sampling contract. It should **not** imply identical
random-number streams or identical posterior draws.

```{r}
backend_capabilities()
validate_backend_environment("rstan")
validate_backend_environment("cmdstanr")
```

An optional compiler smoke test can be requested explicitly and is not run in
this vignette:

```{r eval=FALSE}
validate_backend_environment("rstan", compile_test = TRUE)
validate_backend_environment("cmdstanr", compile_test = TRUE)
```

## Posterior-summary parity

Parity is evaluated relative to Monte Carlo uncertainty rather than exact draw
identity. The data-frame interface below makes the rule transparent and is also
useful for archived summary comparisons.

```{r}
rstan_summary <- data.frame(
  variable = c("b_Intercept", "b_conditiontreatment"),
  mean = c(-0.60, 0.40),
  sd = c(0.20, 0.15),
  mcse_mean = c(0.01, 0.01)
)

cmdstanr_summary <- data.frame(
  variable = c("b_Intercept", "b_conditiontreatment"),
  mean = c(-0.59, 0.41),
  sd = c(0.21, 0.15),
  mcse_mean = c(0.01, 0.01)
)

parity <- audit_backend_parity(
  rstan_summary,
  cmdstanr_summary
)
parity
plot(parity)
```

With real fits, the same function obtains posterior summaries from each fit:

```{r eval=FALSE}
parity <- audit_backend_parity(
  fit_rstan,
  fit_cmdstanr,
  variables = c("b_Intercept", "b_conditiontreatment")
)
```

## Object-schema compatibility

A stable release also needs to know when serialized object structure changes.
Schema capture records structure rather than values.

```{r}
contract <- create_model_contract(
  "binary", "selected", "participant_id",
  condition_col = "condition"
)

schema <- capture_gp3bayes_schema(contract)
schema

validation <- validate_gp3bayes_schema(contract, schema)
validation
```

Freezing does not write anything unless a path is explicitly provided:

```{r}
frozen_schema <- freeze_gp3bayes_schema(schema)

schema_file <- tempfile(fileext = ".rds")
freeze_gp3bayes_schema(frozen_schema, schema_file)
read_gp3bayes_schema(schema_file)
unlink(schema_file)
```

A schema match is a compatibility check only. It says nothing about numerical
identity, statistical adequacy, or scientific validity.
