---
title: "End-to-end WRB 2022 classification with full names"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{End-to-end WRB 2022 classification with full names}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment  = "#>"
)
library(soilKey)
```

This vignette walks the full WRB 2022 (4th edition) classification flow on the canonical Ferralsol fixture, end to end -- from a raw `PedonRecord` to the complete name, built by the rules of Chapter 2.2, with both **principal** and **supplementary** qualifiers in the canonical parenthesised form.

The Ferralsol fixture represents a typical Brazilian *Latossolo* (gneiss-derived, Mata Atlântica). Since v0.9.217 the qualifier lists are those of WRB 2022 Chapter 4 and the name is built by the rules of Chapter 2.2, and `classify_wrb2022()` resolves it to:

```
Geric Rhodic Ferralsol (Clayic, Epic, Eutric, Ferric, Humic)
```

We will inspect each step that produces that name.

# 1. Build the pedon

The canonical fixture exposes a published-quality profile. Use it as the working pedon.

```{r build-pedon}
pr <- make_ferralsol_canonical()
pr
```

A glance at the horizons and chemistry:

```{r horizons-table}
knitr::kable(
  pr$horizons[, .(top_cm, bottom_cm, designation,
                  munsell_hue_moist, munsell_value_moist, munsell_chroma_moist,
                  clay_pct, oc_pct, cec_cmol, bs_pct,
                  ph_h2o, ph_kcl)]
)
```

Notable features for WRB key:

- Clay 50-60 % throughout, hue 2.5YR, low chroma -> ferralic-like with reddish tint;
- OC 2.0 % at the surface, decreasing with depth;
- Low CEC (5-8 cmol+/kg fine earth) and low BS (13-24 %);
- pH H2O 4.7-4.9, pH KCl 4.0-4.2 -> delta pH negative (no Posic).

# 2. Run the WRB key

`classify_wrb2022()` walks the canonical Ch 4 RSG order (HS -> AT -> ... -> RG) and returns the first RSG whose tier-2 gate is satisfied.

```{r classify}
res <- classify_wrb2022(pr)
res
```

The returned `ClassificationResult` carries:

- `$rsg_or_order` -- the assigned Reference Soil Group (here, **Ferralsols**);
- `$name`        -- the full name with principal and supplementary qualifiers;
- `$qualifiers`  -- the resolved principal and supplementary lists, plus the per-qualifier trace;
- `$trace`       -- the RSG-by-RSG key trace, including which RSGs failed before the assignment;
- `$evidence_grade` -- A through E (or NA when no horizon carries a soil property), summarising the provenance of the classification.

# 3. Inspect the principal qualifier resolution

After the RSG is assigned, the resolver walks the RSG's list of principal qualifiers from WRB 2022 Chapter 4, in its ranked order. For Ferralsols (p. 110) the list is `Ferritic, Gibbsic, Rhodic/Xanthic, Geric, Nitic, Pretic, Gleyic, Stagnic, Profundihumic, Mollic/Umbric, Acric/Lixic, Skeletic, Haplic`. Qualifiers separated by a slash are mutually exclusive, or the later ones are redundant, so only the first that applies is used.

```{r resolve-principal}
qres <- resolve_wrb_qualifiers(pr, "FR")
qres$principal
```

Principal qualifiers are written right to left: "the uppermost qualifier in the list is placed closest to the name of the RSG" (Chapter 2.2). Rhodic ranks above Geric, so the name reads *Geric Rhodic Ferralsol*. Their ranks in the list:

```{r principal-table, echo = FALSE}
fr <- unlist(yaml::read_yaml(system.file("rules/wrb2022/qualifiers.yaml",
                                         package = "soilKey"))$rsg_qualifiers$FR$principal)
rank <- vapply(qres$principal, function(q)
  which(vapply(strsplit(fr, "/", fixed = TRUE), function(a) q %in% a, logical(1)))[1],
  integer(1))
data.frame(Qualifier = qres$principal, `Rank in Chapter 4` = rank,
           check.names = FALSE, row.names = NULL)
```

The `trace` slot keeps every Ch 4 principal that was tested, including those that failed. Useful for diagnostic debugging:

```{r principal-trace}
trace_df <- do.call(
  rbind,
  lapply(names(qres$trace), function(q) {
    t <- qres$trace[[q]]
    data.frame(qualifier = q,
               passed    = if (is.null(t$passed)) NA else t$passed,
               note      = t$note %||% "")
  })
)
head(trace_df, 12)
```

# 4. Inspect the supplementary qualifier resolution

Supplementary qualifiers go in brackets after the RSG name. They are not ranked: the texture qualifiers come first, the others "in the order of the alphabet", by qualifier rather than subqualifier (Chapter 2.2).

```{r resolve-suppl}
qres$supplementary
```

Ochric does not appear: the Ferralsol list has `Humic/Ochric`, and Humic applies first. Each tag, with the source the resolver cites:

```{r suppl-table, echo = FALSE}
data.frame(
  Qualifier = qres$supplementary,
  Reference = vapply(qres$supplementary, function(q) {
    fn <- get0(paste0("qual_", tolower(q)), envir = asNamespace("soilKey"))
    r <- tryCatch(if ("rsg_code" %in% names(formals(fn))) fn(pr, rsg_code = "FR") else fn(pr),
                  error = function(e) NULL)
    if (is.null(r$reference)) "" else r$reference
  }, character(1)),
  row.names = NULL
)
```

# 5. Compose the name

`format_wrb_name()` glues principal and supplementary into the canonical form:

```{r format}
format_wrb_name(
  rsg_name      = "Ferralsols",
  principal     = qres$principal,
  supplementary = qres$supplementary
)
```

This is exactly the string returned by `classify_wrb2022()$name`.

# 6. Redundant and sibling qualifiers

"Qualifiers conveying redundant information are not added ... For example, Eutric is not added if the Calcaric qualifier applies" (Chapter 2.2). The resolver drops Eutric, and its subqualifiers such as Hypereutric, when Calcaric or Dolomitic applies:

```{r redundant}
soilKey:::.drop_redundant_qualifiers(c("Calcaric", "Hypereutric"),
                                     c("Calcaric", "Hypereutric"))
```

When several qualifiers of one family pass (Hypercalcic, Calcic, Protocalcic), only the most specific is kept, in the principal and in the supplementary list:

```{r families}
str(soilKey:::.wrb_qualifier_families)
soilKey:::.suppress_qualifier_siblings(
  c("Mollic", "Hypercalcic", "Calcic", "Protocalcic", "Cambic")
)
```

# 7. Evidence grade

`classify_wrb2022()` reports an `evidence_grade` summarising the provenance of every attribute used in the classification. **A** means every value was measured; **B** to **E** mark spectra-predicted, prior-inferred, VLM-extracted and user-assumed values; **NA** means no horizon carries a soil property at all.

```{r grade}
res$evidence_grade
```

The Ferralsol fixture has all measured values, so the grade is **A**. The `v01_getting_started` vignette shows how `pedon$add_measurement()` with `source = "extracted_vlm"` or `source = "predicted_spectra"` lowers the grade -- so you always know how robust the classification is.

# 8. Render a self-contained pedologist-facing report

The `report()` generic takes a `ClassificationResult` (or a list of them, or a `PedonRecord` -- in which case all three keys are run automatically) and writes a single-file HTML report with inline CSS, no external network requests, suitable for archiving with a laudo. The PDF path goes through `rmarkdown::render()` and requires a working LaTeX engine.

```{r report, eval = FALSE}
# Pass the three classifications as a list:
results <- list(
  classify_wrb2022(pr),
  classify_sibcs(pr, include_familia = TRUE),
  classify_usda(pr)
)
report(results, file = "perfil_ferralsol.html", pedon = pr)

# Or pass the pedon directly and let report() run the three keys:
report(pr, file = "perfil_ferralsol.html")

# Same content as PDF (requires LaTeX):
# report(pr, file = "perfil_ferralsol.pdf")
```

The HTML output includes: the cross-system summary, the full key trace per system, qualifiers (principal + supplementary), evidence grade, ambiguities, missing data, the horizons table, and the per-source provenance summary. `ClassificationResult$report(file)` is the R6-method-style equivalent and delegates to the same code.

# 9. Tier-3 strict mode for borderline pedons

By default the per-RSG numerical gates apply soilKey's regionally calibrated thresholds. For pedons that sit close to an RSG boundary, `classify_wrb2022()` accepts a `strict` argument that strengthens seven Tier-3 gates toward the canonical WRB 2022 Chapter 4 intent (e.g. the Vertisol overlying-clay floor rises from 30 % to 35 %, the Chernozem base-saturation floor from 50 % to 80 %).

```{r strict, eval = FALSE}
# A profile with 32 % clay above a vertic horizon: a Vertisol under the
# default gate, but below the 35 % strict floor.
classify_wrb2022(pr, strict = FALSE)$rsg_or_order  # default
classify_wrb2022(pr, strict = TRUE)$rsg_or_order   # Tier-3 strict
```

`strict = FALSE` (the default) is fully backward compatible -- every canonical fixture classifies identically with and without it. Strict mode only changes genuinely borderline profiles, which makes it a useful sensitivity probe: if a classification is stable across both modes, the assignment is robust. The toggle can also be set globally with `options(soilKey.rsg_strict = TRUE)` (this is what the Shiny Pro app's Settings tab does), and each RSG gate records the effective threshold in its `DiagnosticResult` evidence.

# Summary

```{r summary, echo = FALSE}
cat(sprintf("WRB 2022 name : %s\n", res$name))
cat(sprintf("Assigned RSG  : %s\n", res$rsg_or_order))
cat(sprintf("Principal     : %s\n", paste(res$qualifiers$principal,     collapse = ", ")))
cat(sprintf("Supplementary : %s\n", paste(res$qualifiers$supplementary, collapse = ", ")))
cat(sprintf("Evidence grade: %s\n", res$evidence_grade))
```

The `v03_cross_system_correlation` vignette runs the same profile through the Brazilian SiBCS and the USDA Soil Taxonomy keys and shows the alignment between the three classifications.
