# Metric dictionary

Every metric the API returns, with its conceptual definition, operational
definition, formula, range, required inputs, missing-data behaviour, window and
weighting assumptions, permitted interpretation and **prohibited
interpretation**.

The prohibited-interpretation column is normative. It states what the number
does *not* license you to conclude, and it is reproduced in the API responses
themselves so it travels with the data.

Algorithm versions in force: `core-1.0.0`, `lcc-1.1.0`, `iccc-1.1.0`,
schema `1.0.0`.

---

## Conventions

**Missing values are `null`, never zero.** Every `null` is accompanied by a
quality flag naming the reason. A zero means "measured, and it was zero".

**Similarity scale.** Layer 2 uses cosine similarity mapped to `[0,1]` by
`S = (cos + 1) / 2`. On that scale two orthogonal representations sit at `0.5`,
identical ones at `1.0`, opposed ones at `0.0`. All thresholds are expressed on
this scale. This bounded transformation is **not a probability calibration**;
unrelated texts need not have orthogonal embeddings. Empty, zero-norm,
nonfinite or dimension-inconsistent vectors are rejected explicitly, not mapped
to fabricated neutral similarity. A cancelling centroid has no direction and
returns `null` for centroid-derived detail variants.

**Token provenance.** Every token count carries a source: `provider_reported`,
`locally_counted` or `estimated`. A missing provider figure is never silently
replaced by a local estimate.

---

# Layer 1 — content-agnostic interaction analytics

## Structural text measures

| Field | Definition | Range | Missing behaviour |
|---|---|---|---|
| `characterCount` | Unicode code points in the contribution | ≥ 0 | `null` if text is not stored |
| `nonWhitespaceCharacterCount` | Code points excluding whitespace | ≥ 0 | as above |
| `wordCount` | Language-appropriate segments: whitespace/punctuation tokens for alphabetic scripts, one per character for Han/Kana/Hangul | ≥ 0 | as above |
| `sentenceCount` | Segments terminated by `. ! ? 。 ！ ？ …` or a blank line, with fenced code removed | ≥ 0 | `0` for empty text |
| `paragraphCount` | Blocks separated by a blank line | ≥ 0 | |
| `meanSentenceLength` | `wordCount / sentenceCount` | > 0 | `null` when there are no sentences |
| `questionCount` | Sentences ending in a question mark, plus sentences opening with an English interrogative and at least three words | ≥ 0 | |
| `listItemCount`, `headingCount`, `urlCount`, `codeBlockCount` | Markdown-structure counts | ≥ 0 | |
| `repeatedNgramProportion` | Share of 4-gram positions whose gram occurs more than once | 0–1 | `null` below 8 tokens |
| `language`, `languageConfidence` | Dominant writing system, and its share of script-bearing characters | — | `und` when no script characters |
| `codeSwitchIndicator` | A second script accounts for ≥ 10% of characters | boolean | |

**Prohibited interpretation.** Length, structure and markup counts describe
form. They are not measures of effort, quality, clarity, or informativeness.
`questionCount` counts interrogative *form*, not curiosity or confusion.

---

## Lexical density

**Construct.** Proportion of a contribution carried by content words.

**Formula.**

```
LD = (nouns + lexical verbs + adjectives + adverbs) / word tokens
```

**Operationalisation in this version.** English is implemented as
`english_closed_class_exclusion_v1`: a word token is a content word unless it
appears in a curated closed-class lexicon (determiners, pronouns, auxiliaries,
prepositions, conjunctions, particles). This requires no statistical tagger and
is fully reproducible, but it counts every open-class token as content,
including proper nouns and numerals. The method string is returned with every
result so tagger-based and lexicon-based figures can never be confused.

**Range** 0–1. **Required inputs** stored raw text, a supported language.

**Missing behaviour.** Languages with no registered POS adapter return `null`
with `UNSUPPORTED_LINGUISTIC_MEASURE`. Chinese returns segmentation and
character measures but `null` density unless a Chinese POS adapter is
registered. Empty text returns `null` with `INSUFFICIENT_TEXT`.

**Prohibited interpretation.** Lexical density is **not** informativeness, not
lexical diversity, and emphatically **not** ICCC Communication Density. A dense
contribution is not a better one.

---

## Lexical diversity

**Formulas.**

```
TTR   = unique normalised types / tokens
RTTR  = types / sqrt(tokens)                    (Guiraud root TTR)
CTTR  = types / sqrt(2 · tokens)                (Carroll corrected TTR)
MATTR = mean TTR over a sliding 50-token window
uniqueLemmasPer100Words = 100 · unique crude lemmas / tokens
```

**Range** TTR and MATTR 0–1; RTTR and CTTR unbounded above.

**Missing behaviour.** Below 10 word tokens every field is `null` with
`INSUFFICIENT_TEXT`, because TTR is strongly length-dependent. MATTR is `null`
below 50 tokens. The lemmatiser is a rule-based suffix stripper, declared in the
method string.

**Prohibited interpretation.** Diversity is not vocabulary size, education,
competence or sophistication. TTR falls as text lengthens; comparing raw TTR
across contributions of different lengths is invalid — use MATTR.

---

## Token production ratios

For human prompt `Uᵢ` (visible tokens), total provider input `Pᵢ`, and AI
completion `Cᵢ` (visible tokens):

| Metric | Formula | Meaning | Range |
|---|---|---|---|
| Immediate Expansion Ratio `ERᵢ` | `Cᵢ / Uᵢ` | AI visible output per unit of new visible human input | > 0 |
| API Amplification Ratio `ARᵢ` | `Cᵢ / Pᵢ` | Output relative to the *full* provider input, including history and instructions | > 0 |
| Human Share `HS` | `ΣUᵢ / (ΣUᵢ + ΣCᵢ)` | Proportion of visible language produced by humans | 0–1 |
| AI-to-Human Production Ratio `AHR` | `ΣCᵢ / ΣUᵢ` | Visible output balance | > 0 |
| Follow-up Compression Ratio `FCRᵢ` | `Uᵢ₊₁ / Cᵢ` | Next human contribution relative to the preceding completion | > 0 |

**Missing behaviour.** A zero denominator returns `null` with
`ZERO_DENOMINATOR` — never `Infinity`, never `NaN`. `AR` is `null` whenever
`totalApiInputTokens` was not supplied.

**Prohibited interpretation.** These are volume ratios. A high `AHR` does not
mean the AI contributed more *value*, and a low `HS` does not mean the human
disengaged or ceded authorship. `FCR` is not a measure of satisfaction: a short
follow-up may mean "that answered it" or "that was useless".

---

## Timing

```
TTFTᵢ  = t(AI first token, i) − t(human submit, i)
GDᵢ    = t(AI last token, i)  − t(AI first token, i)
E2Eᵢ   = t(AI last token, i)  − t(human submit, i)
TPOTᵢ  = GDᵢ / (Cᵢ − 1)                        for Cᵢ > 1
HLᵢ₊₁  = t(next human submit) − t(previous AI last token)
HL100ᵢ = HLᵢ₊₁ / (Cᵢ / 100)
```

`TTFT` and `E2E` are anchored on the preceding **human** submission, not on the
AI record's own timestamp.

**Aggregates.** Raw and active-session distributions, each with count, min, max,
mean, median, geometric mean, and the 25th, 50th, 75th and 90th percentiles.
The geometric mean excludes non-positive observations; latency distributions are
right-skewed, so the median and geometric mean are the honest summaries.

**Sessions.** A gap larger than `SESSION_GAP_MINUTES` (default 30) opens a new
session and raises `CROSS_SESSION_GAP`. Gaps are **retained and flagged, never
deleted**. `ACTIVE_RESPONSE_MAX_MINUTES` (default 30) bounds the active-session
distribution.

**Prohibited interpretation.** `HL` is named `humanAdjacentTurnLatency` and is
**not** reading time, thinking time, deliberation, engagement or attention. It
contains reading, deliberation, typing, interruption, multitasking and plain
inactivity in unknown proportions. `TTFT` and `GD` are properties of the serving
infrastructure, not of the conversation.

---

## Latency versus completion length

**Model.** `log(1 + HLᵢ₊₁) = β₀ + β₁·Cᵢ + ε`, fitted by OLS; with ≥ 12
observations a Huber robust fit replaces it. Returns the slope per 100
completion tokens, sample size, R², a 95% confidence interval, binned non-linear
summaries and a piecewise-linear spline over bin midpoints.

**Missing behaviour.** Below 5 usable observations the method is
`insufficient_data` and every estimate is `null`. Observations outside the
active-session window are excluded and counted in `excludedCrossSessionGaps`.

**Prohibited interpretation.** The slope must **not** be read as reading speed,
cognitive effort, attention, comprehension or engagement. It is an association
between two observable quantities in one thread, usually with a small sample.

---

## Speech acts and structural derivatives

Classification is multi-label over functional segments, using schema-constrained
LLM output. See [`speech-act-taxonomy.md`](speech-act-taxonomy.md).

| Metric | Formula | Range |
|---|---|---|
| Speech-act entropy | `H = −Σ pₖ log pₖ` (nats) | ≥ 0 |
| Normalised entropy | `H / log K` over `K` observed categories | 0–1 |
| Repair rate | `(corrections + reformulations + revision requests + misunderstanding signals) / eligible human turns` | ≥ 0 |
| Acceptance rate | `(acceptance + agreement + positive feedback) / eligible human turns` | ≥ 0 |
| Rejection rate | `(rejection + disagreement + negative feedback) / eligible human turns` | ≥ 0 |
| Transition matrix | Row-normalised act → act counts | rows sum to 1 |
| Participant transition matrix | Row-normalised `actor:act` → `actor:act` | rows sum to 1 |
| Initiative balance | Counts over `initiate`, `respond`, `repair`, `manage` | ≥ 0 |

Normalised entropy is `null` when only one category was observed: the normaliser
would be zero.

**Prohibited interpretation.** **Acceptance is not proof of AI answer quality**
— people accept wrong answers. **Repair is not necessarily evidence of system
failure** — repair is normal, healthy interactional work, and its absence can
signal disengagement rather than success. Entropy describes variety of
communicative function, not richness of thought.

---

## Accommodation, participation and trajectory

| Metric | Definition | Range |
|---|---|---|
| Turn-length accommodation | Pearson correlation between a participant's contribution length and the immediately preceding contribution of another participant | −1 to 1 |
| Timing accommodation | The same correlation over end-to-end durations | −1 to 1 |
| Participation symmetry | `1 − Σ\|shareₚ − 1/N\| / (2(1 − 1/N))` | 0–1 |
| Gini coefficient | Concentration of turn counts | 0–1 |
| Trajectory | Early/middle/late thirds: turns, mean words, mean human latency, human share, top acts | — |

Accommodation is `null` below 3 usable pairs; symmetry is `null` below 2
participants.

**Prohibited interpretation.** Accommodation here is statistical covariation of
observable quantities. It is **not** rapport, alignment, persuasion, social
influence or linguistic convergence in the sociolinguistic sense. Symmetry is
not fairness, and asymmetry is not domination — an expert answering questions
produces asymmetry by design.

---

# LCC — Learner's Characteristic Curves

**Applicability.** Requires `tutorial_dyad` or `group_tutoring`, at least one
participant with the `learner` role, at least one tutor role, a current
instructional question, and a versioned reference model with at least one
expectation. Unmet requirements return `not_applicable` with reasons — never a
fabricated curve.

**Dimensions.** Each semantic unit is scored for relevance `R ∈ [0,1]` against
the reference model's expectations, and novelty `N ∈ [0,1]` against the
learner's own prior units and already-covered reference points. Both use
piecewise-linear membership between versioned thresholds (`relevanceLower`
0.58, `relevanceUpper` 0.78, `noveltyLower` 0.62, `noveltyUpper` 0.85 on the
normalised similarity scale).

**Quadrants.**

```
RN = R·N            relevant and new
RO = R·(1−N)        relevant and previously covered
IN = (1−R)·N        irrelevant and new
IO = (1−R)·(1−N)    irrelevant and previously seen
RN + RO + IN + IO = 1
```

| Preferred derived field | Formula | Deprecated compatibility alias |
|---|---|---|
| `relevantNewMass` | `RN` | `currentCorrectContribution` |
| `offReferenceNewMass` | `IN` | `currentWrongContribution` |
| `relevantMass` | `RN + RO` | `accumulatedCorrectContribution` |
| `offReferenceMass` | `IN + IO` | `accumulatedWrongContribution` |
| `referenceAlignmentScore` | relevant mass − off-reference mass, range −1 to 1 | `overallScore` |

Legacy fields retain the same values; their names do **not** establish factual
correctness. New artifacts emit both naming sets, including matching nulls.

"Accumulated" means *this contribution's* mass associated with currently-new
plus previously-established content. It is **not** a running sum over the
thread. Session totals are stored separately as `sessionTotalRN` and siblings,
and expectation coverage retains the maximum per-turn matched relevance mass,
not an additive sum. Repeating identical partial evidence cannot increase this
maximum. This conservative summary cannot infer complementary subpoint coverage
unless those subpoints are separately modeled as expectations. Misconception
strength accumulates novel off-reference match mass; it is not a diagnostic
probability. Neither summary measures mastery or correctness.

**Methods.** `hybrid` (preferred) segments into semantic units, scores each, and
aggregates weighted by unit length. `factor_product` scores the whole
contribution from its turn-level representation. `direct_semantic_classification`
assigns each unit to a single dominant quadrant.

**Unmapped content.** Irrelevant content whose best misconception similarity is
below `misconceptionMapping` (0.72) is **never** forced into a known
misconception. It is reported as `unmappedIrrelevantNew` /
`unmappedIrrelevantOld` with `LCC_UNMAPPED_IRRELEVANT_CONTENT`.

**Prohibited interpretation.** "Irrelevant" means *off the current instructional
goal*, not meaningless, wrong or unimportant — a brilliant tangent scores IN.
The overall score is **not** mastery, learning gain, ability or effort. LCC
validity depends on the quality of the reference model as much as on the
classifier, and neither has been externally validated here.

---

# ICCC — Individual Conversation Characteristics Curves

Input structure `Sₜ = (pₜ, vₜ, lₜ, gₜ, t)`. Weights are
`w_tj = e^(−λ·d(t,j))` for exponential decay, `1` inside the window for
`rolling_window`, and `1` for `cumulative`. Distance `d` is measured in
contributions, seconds or minutes; the unit and λ are persisted with every
result.

### Participation

```
s_p,t = Σ_{j∈Wₜ} w_tj·I(pⱼ=p) / Σ_{j∈Wₜ} w_tj
e_t   = 1 / N_t                      (N_t = active participants in the window)
P_p,t = s_p,t / e_t
```

`P = 1` is an equal turn share, `P > 1` above it, `P < 1` below. Also returned:
centred participation `s − e`, visible-token participation, semantic-unit
participation and addressed participation. **Turn participation is the default
curve; production and being addressed are never combined without explicit
configuration.**

**Prohibited interpretation.** Not engagement, effort, leadership or value
contributed. A moderator and a monopoliser can produce the same number.

### Overall Responsivity

```
B_p,t = Σ w_tj·a_tj·S(lₜ,lⱼ) / Σ w_tj·a_tj      over prior contributions by others
```

`a_tj` is an adjacency weight from target resolution (explicit/reply/address 1.0,
inferred 0.6, group default 0.3, unknown 0). Both the unweighted and the
targeting-adjusted values are returned. Range 0–1.

The adjusted curve is a conditional mean: uniform positive adjacency weights
cancel, including when there is only one target. Detail fields separately expose
`adjacencyEvidenceStrength = Σ(w·a)/Σw` and
`adjacencyWeightedSimilarity = Σ(w·a·S)/Σw` over eligible prior contributions by
others. These retain adjacency magnitude but are not calibrated probabilities.
With no positive adjacency weight, the raw curve falls back to the recency-weighted
all-other similarity mean, and `usedUntargetedFallback` is true. The legacy detail
name `unweighted` means no adjacency weighting; recency weighting still applies.

**Prohibited interpretation.** Responsivity is **not agreement**. A correction, a
rebuttal or a flat contradiction can be maximally responsive.

### Internal Cohesion

```
C_p,t = Σ_{j<t, pⱼ=p} w_tj·S(lₜ,lⱼ) / Σ_{j<t, pⱼ=p} w_tj
```

Also returns maximum self-similarity and similarity to the participant's history
centroid. Range 0–1.

**Prohibited interpretation.** High cohesion can be continuity *or* repetition;
low cohesion can be exploration, adaptation, topic change *or* incoherence. No
value judgement attaches in either direction.

### Social Impact

```
r_ij  = w_ij·a_ij·S(lᵢ,lⱼ)                     for later j by other participants
Dᵢ    = Σ_{j∈Fᵢ, pⱼ≠pᵢ} r_ij                   contribution level
D_p,t = Σ_{i∈Wₜ, pᵢ=p} w_ti·Dᵢ / Σ w_ti        participant level
```

Also returns direct replies triggered, distinct responders, semantic response
strength, response depth, response persistence, follow-up token volume and
median time to follow-up.

**State machine.** `provisional → stabilizing → final`, driven by how many
contributions have followed (3 for stabilizing, 8 for final). Provisional points
carry `ICCC_PROVISIONAL_SOCIAL_IMPACT` and
`ICCC_FORWARD_WINDOW_INCOMPLETE`. When new contributions arrive, every still-open
window is recalculated and a **new versioned revision** is published; history is
never mutated.

**Prohibited interpretation.** High Social Impact is **not** benefit, quality or
influence-for-good. Confusing, wrong or inflammatory contributions reliably
trigger many responses.

### Newness

```
E^max      = 1 − max_{j<t} S(lₜ,lⱼ)
E^centroid = 1 − S(lₜ, centroid(U_{t−1}))
E^window   = 1 − Σ w_tj·S(lₜ,lⱼ) / Σ w_tj
```

Reported separately against the participant's own history, against other
participants, and against the whole discussion. Range 0–1.

**Prohibited interpretation.** Newness is **not** usefulness, relevance,
correctness or creativity. Off-topic noise is maximally new.

### Communication Density

```
F^unit = (semantic units in lₜ / visible tokens in lₜ) × 100
F^new  = (non-redundant semantic units / visible tokens) × 100
```

A unit is redundant when its similarity to any earlier unit reaches 0.82.

**Missing behaviour.** When semantic-unit extraction is unavailable the value is
`null` with `ICCC_INSUFFICIENT_SEMANTIC_UNITS`. **Lexical density is never
substituted under this name.**

**Prohibited interpretation.** Not lexical density, and not a measure of quality
or of how much the contribution was worth saying.

---

## Smoothing and normalisation

Raw curve points are **always** preserved; smoothed and normalised series are
additional views written to separate fields.

Smoothing: none, simple moving average, EWMA `Z_t = αX_t + (1−α)Z_{t−1}`,
cumulative mean.

Normalisation: none; theoretically anchored (per-metric defined range);
within-thread min-max; within-participant z-score; cohort-reference z-score
(requires supplied cohort statistics, otherwise `null`).

Thread-local schemes raise `ICCC_NORMALIZATION_NOT_COMPARABLE`. Curves from
different semantic models, algorithm versions or normalisation schemes are never
compared without an explicit incompatibility warning.

---

## Cross-model patterns (group tutoring)

In `lcc_and_iccc` mode both engines run over the same shared artifacts and are
stored separately. Descriptive co-occurrences include high RN with low Social
Impact (reference-aligned and little followed up), high RN with high Overall Responsivity, high RO
with high Internal Cohesion, and high IN with high Social Impact (off-target and
influential).

**Prohibited interpretation.** These are descriptive co-occurrences. They are
not causal, not pedagogical conclusions, and the two models are never combined
arithmetically.

---

## Quality flags

`MISSING_TIMESTAMP`, `INVALID_TIMESTAMP_ORDER`, `MISSING_PROVIDER_USAGE`,
`TOKEN_COUNT_ESTIMATED`, `INSUFFICIENT_TEXT`, `UNSUPPORTED_LANGUAGE`,
`UNSUPPORTED_LINGUISTIC_MEASURE`, `ZERO_DENOMINATOR`, `CROSS_SESSION_GAP`,
`LLM_CLASSIFICATION_PENDING`, `LLM_CLASSIFICATION_FAILED`,
`LOW_CLASSIFICATION_CONFIDENCE`, `OUT_OF_ORDER_TURN`, `DUPLICATE_TURN`,
`MISSING_PARENT_TURN`, `UNKNOWN_TARGET`, `SEMANTIC_MODEL_UNAVAILABLE`,
`INCOMPATIBLE_EMBEDDING_VERSION`, `RECALCULATION_REQUIRED`,
`LCC_MISSING_REFERENCE_MODEL`, `LCC_MISSING_EXPECTATIONS`,
`LCC_UNMAPPED_IRRELEVANT_CONTENT`, `LCC_LOW_REFERENCE_MATCH_CONFIDENCE`,
`LCC_INSUFFICIENT_HISTORY`, `ICCC_INSUFFICIENT_HISTORY`,
`ICCC_PROVISIONAL_SOCIAL_IMPACT`, `ICCC_FORWARD_WINDOW_INCOMPLETE`,
`ICCC_INSUFFICIENT_SEMANTIC_UNITS`, `ICCC_LOW_TARGET_CONFIDENCE`,
`ICCC_CROSS_LANGUAGE_COMPARISON`, `ICCC_NORMALIZATION_NOT_COMPARABLE`.

---

## Original constructs versus this implementation

LCC and ICCC are theoretical constructs from the research literature. What this
software provides is one *operationalisation* of them: specific similarity
functions, specific thresholds, specific windows and specific aggregation rules,
all versioned and reproducible.

Reproducible is not the same as validated. The formulas here provide consistent
operational definitions; they are not evidence that the curves predict learning,
group effectiveness or any other outcome. Establishing that requires external
measures and empirical study. See [`evaluation.md`](evaluation.md) for the
harness that measures agreement with human annotation — which is itself a
weaker claim than validity.
