Skip to content

ADR-076: Multi-domain category taxonomy expansion (personal-choice + relational-decision)

Status: Accepted Date: 2026-05-31 Context: ADR-074 ("Pulse as a multi-domain judgment layer") accepted that the architecture supports non-governance domains and scoped the remaining taxonomy work as "add 1–2 new categories: personal-choice, possibly relational-decision" plus "2–3 non-work triggers." That scope was a sketch, not a specification. The analysis that turns it into one lives in the design brief at docs/research/briefs/multi-domain-category-taxonomy-brief.md (commit 0877066), which worked through the final taxonomy, audited all 14 behavioral signals for cross-domain firing, verified the category_patterns structure against the actual code, and engaged the pushback invitation (argue for more or fewer categories). This ADR formalizes the brief's conclusions as canonical decisions, because they affect downstream scenario tagging, the generator validators, the ScenarioCategory type other code references, and future taxonomy debates — and a research brief is findable but an ADR is indexed and canonical.

The four categories today are governance, resource-allocation, team-dynamics, values-culture (ScenarioCategory union, src/lib/ai/scenario-generator.ts:14). The ten triggers live in src/lib/ai/driver-trigger-constants.ts.

At a glance

What it decides: Two categories (personal-choice, relational-decision) and two triggers (personal_crossroads, intimate_disclosure) are added to fill the self-scope and personal-interpersonal gaps the existing four categories leave.

  • Categories are trade-off types, not domainspersonal-choice is a self-scoped cost-bearing tension, not "the personal-life domain," which keeps the taxonomy domain-agnostic
  • No migration, no signal-aggregate change, no category_patterns shape change — new keys are added lazily and existing profiles are unperturbed (verified in code)
  • Rejected splitting personal-choice into health vs. finance — that risk-calibration variance resolves on expertise/confidence (a signal job), not on topic; splitting would break architectural independence
  • Deferred a health_decision_point trigger and the expertise-conditioning signal refinements (R1/R2) until played multi-domain corpus exists to calibrate against
flowchart LR
    subgraph EXIST["Existing 4 (unchanged)"]
        G["governance"]
        R["resource-allocation<br/>(framing widens to personal resources)"]
        T["team-dynamics<br/>(tightens to work-only)"]
        V["values-culture"]
    end
    subgraph NEW["New (+2)"]
        P["personal-choice<br/>self-scoped, cost-bearing"]
        RD["relational-decision<br/>personal interpersonal"]
    end

Two trade-off-type categories are added; the four existing categories stay, with scope clarifications to team-dynamics and resource-allocation.

Decision

Two new categories

personal-choice — a trade-off where the player is the primary affected party and bears the principal cost themselves: life-direction, health, personal finance (the experiment's financial Tier 4–7), lifestyle. Structurally: scope = self/dyad, distance-to-most-affected = self/intimate, authority = full/oversight, visibility = private/dyadic. - Expected drivers (from the existing 8): caution, growth, autonomy, pragmatism dominant; team_harmony rare; principle in health/lifestyle commitments. No driver-enum change. - Expected signal patterns: high identity load (M1) and ideal-actual reference (E14); domain-confidence asymmetry (M3) strongly present and the category's defining measurement challenge (health-deference vs. finance-confidence); time-horizon orientation prominent.

relational-decision — a dyadic or small-group interpersonal trade-off outside a formal work-authority structure: loyalty vs. honesty, disclosure, conflict-avoidance, intimacy. The personal-interpersonal complement to team-dynamics. - Expected drivers: team_harmony (read as interpersonal harmony per ADR-074's mapping), transparency, principle, autonomy. - Expected signal patterns: pragmatic-routing (E13) fires strongest here; persuadability under social (not authority) pressure; authenticity/rationale-choice match (E10); loyalty-vs-merit most legible here.

Two new triggers

Added to TRIGGERS in src/lib/ai/driver-trigger-constants.ts (additive to context_rules / schema A5): - personal_crossroads — a self-scoped life-direction inflection (covers personal-choice). - intimate_disclosure — a relational honesty / secret-keeping pressure (covers relational-decision).

Scope clarifications to existing categories (authoring guidance, not redefinitions)

  • team-dynamics tightens to work/organizational interpersonal coordination under a shared authority structure. With relational-decision added, team-dynamics is no longer the catch-all for anything interpersonal. No reclassification of existing data is forced — all current team-dynamics scenarios are already work-shaped, so the tightening is descriptive of what is there.
  • resource-allocation widens its framing to include personal resources (time, attention, personal money), not only organizational budgets/headcount. A prompt-copy note, not a structural change.

What stays unchanged

  • governance and values-culture — definitions unchanged. Governance's "borderline" cross-domain transfer (ADR-074) is a corpus property (institution-scope-heavy), not a category defect; do not widen the definition to chase rare personal-governance scenarios.
  • All 14 behavioral signals (ADR-024's 12 + pragmatic-routing E13 + ideal-actual-reference E14) — no new aggregate. The set is confirmed cross-domain-complete.
  • category_patterns JSONB shape (src/types/database.ts:948) — no shape change, no migration. It is keyed { [category: string]: {...} }; new keys are added lazily the first time a player plays a category.

The only required type change is adding 'personal-choice' | 'relational-decision' to the ScenarioCategory union, which propagates to the generator's validCategories array and prompt strings.

Rationale

The "category = trade-off type, not domain" guardrail. A category is the canonical tension a scenario is built around; a domain (cube/experiment vocabulary) is the surface the tension is dressed in. The cube doc is explicit that domain is not a cube dimension. personal-choice is therefore not "the personal-life domain" — it is a trade-off type (self-scoped, cost-bearing) that correlates with self/dyad scope on cube axis 5. Holding this distinction is what keeps the taxonomy from collapsing into surface-tagging and preserves the domain-agnostic property ADR-074 depends on.

The self-scope gap is the actual hole. All four existing categories are other-affecting (institution, a resource pool, a team, a culture). None has a clean home for a self-scoped trade-off where the player is the most-affected party. The cube corpus findings confirm this structurally: governance is ~75% institution-scope and personal/self/dyad scope is "absent" from the governance corpus. personal-choice fills the gap; relational-decision fills the personal-interpersonal gap that team-dynamics (work-only) leaves.

Architectural-independence finding (measurement schema). The schema work established that the schema's design dimensions — categories, signals, closures, measured outcomes — are mutually independent and compose additively without cross-contamination. This is the load-bearing support for "categories are additive without conflict": new categories slot in without perturbing signals or other categories.

In-code verification that category_patterns is additive without migration. Confirmed directly, not merely asserted from the schema: keys are added lazily in updateCategoryPatterns (player-model.ts:654); migrateProfile handles missing fields gracefully (player-model.ts:99); and calculateModelConfidence (player-model.ts:858) counts only played categories (Object.keys(categoryPatterns).length) with the category-coverage component already capping at 0.15 (reached at ~4 categories). Adding two categories to the union therefore does not inflate or perturb existing profiles — they gain credit only if the player actually plays the new categories.

Alternatives Considered

  • A third category — split personal-choice into health vs. finance (e.g. personal-wellbeing + personal-finance). Rejected. The motivating defect is real: the experiment's clearest finding is that risk calibration splits (CoachJ is risk-tolerant in finance, "math is the math"; risk-conservative in acute health, defers to the doctor), and a unified category's per-category risk_tolerance scalar averages two opposite regimes into mush. But that variance resolves on expertise / authority-deference, not on topic — i.e. on cube-C2 (expertise requirement) and its player-side correlate M3 (domain-confidence asymmetry). So it is a signal-conditioning job (refinement R1, see Discussion), not a taxonomy job. Splitting the category to fix a signal-shape problem would smuggle a measured-outcome (M3) into the substrate taxonomy and break the architectural-independence claim. If we split a category every time a signal varies within it, category count is unbounded. Keep personal-choice unified; fix the signal.

  • A third trigger — health_decision_point (floated by ADR-074's "2–3 triggers"). Deferred (decision confirmed by CoachJ). Same principled reason as the category split: cube-C2 (expertise-requirement) × M3 (domain-confidence-asymmetry) × the existing universal relational_proximity trigger already discriminate health-deference patterns. A dedicated health trigger creates trigger redundancy and violates the architectural-independence claim. Trigger condition for revisit: an explicit scenario-author signal, during corpus tagging, that the existing machinery is insufficient for health-specific tagging.

  • Zero new categories (stay at 4). Rejected — leaves the self-scope gap unfilled; S6 (health overhaul) and S8 (debt-vs-invest) have nowhere clean to land.

  • Four or more new categories (one per experiment life-surface: career/health/relational/financial). Rejected as the category-as-surface error (AP3). Career is not a category — a career scenario can be resource-allocation, values-culture, or team-dynamics. Two trade-off-type categories cover all four life-surfaces.

Discussion

This ADR preserves the brief's pushbacks and deliberation so future readers see not just what was decided but how.

The brief engaged ADR-074's explicit pushback invitation ("the 1–2 scope might be wrong — argue for more or fewer"). It argued for exactly two, and the harder-won half of that is the rejection of a third: the temptation to split personal-choice is strong because the risk-calibration split is the experiment's single cleanest finding. The discipline that resisted the split is the architectural-independence claim — categories and signals are orthogonal, so signal variance is fixed on the signal axis.

Anti-pattern AP1 — the per-category risk_tolerance scalar. The expansion surfaces a latent flaw in the existing structure (per the "changes-trigger-re-audit" discipline). category_patterns[cat].risk_tolerance (database.ts:952) is a single 0–1 scalar. The experiment proved risk-tolerance is expertise-conditional, not category-stable; for personal-choice (unifying deferential-health and confident-finance) the scalar averages two regimes into an uninformative midpoint. The scalar was tolerable while the corpus was governance-only (one regime). Recommendation: do not split the category to rescue the scalar (that is AP2); treat risk_tolerance as deprecated-for-exposure in personal-choice and route the real signal through E5 calibration's by_expertise breakout once R1 ships; flag for a dedicated re-audit when R1 lands. Does not block this ADR.

Refinements R1 and R2 — deferred as substrate-gated. - R1 — confidence-calibration (E5) and persuadability (E7) need an expertise / domain-confidence conditioning dimension (a by_expertise breakout keyed to cube-C2, parallel to the existing by_category breakout). This is the experiment's Finding 1 made schema-precise, anchored to cube-C2 / M3, and already tracked as the schema's parked question Q4d. It is not a new signal aggregate. Gated on cube-C2 tagging reaching the corpus. - R2 — a candidate physical attention sub-category on the attention model (E16), to mirror cube-C1's physical cost category for health scenarios. Speculative; defer until corpus shows players reliably noticing/ignoring physical stakes in a way the existing six attention categories miss (ship-and-observe).

Why no new signal aggregate is the right call. All 14 signals fire cross-domain. The decisive evidence: the two most recent signals (E13 pragmatic-routing, E14 ideal-actual-reference) were discovered in the personal-domain experiment and cross-checked back into governance. The set's own growth history demonstrates it is cross-domain-complete rather than governance-shaped.

CoachJ's "do the hard work sooner" instinct, and how the brief split the response. The instinct is partly right and partly premature, so the brief split it: - Do now (cheap, additive, avoids rework): the taxonomy decision, the ScenarioCategory union change, the two triggers, the authoring-guidance clarifications. Corpus is about to be authored; tagging 50–100 scenarios against the wrong category set and re-tagging later is the expensive path. Getting tags right at authoring time is nearly free. - Defer (substrate-gated, ship-and-observe): R1 (= Q4d) and R2. Both need a played multi-domain corpus to calibrate against; building them now optimizes against hypothetical signal. ADR-074's own revisit trigger ("after 50+ non-governance scenarios, signals show drift that doesn't recover with retuning") is the right gate.

The clean rule: scaffold the substrate now; recalibrate the signals on observed data. This matches the schema's own staging — Q4b (category-stratification) is "ship now, no substrate gate"; Q4d (cube-C2 stratification) is substrate-gated.

On model_confidence sharing across personal/work categories (an open question the brief answered). They must not share. model_confidence is one global number; per-category confidence is a separate, sparser quantity derivable from games_in_category. Surfacing the global number against a thinly-sampled personal category over-claims. Per-category exposure must gate on games_in_category-derived N (schema Convention 6), never borrow the global score.

Consequences

  • Scenario authors adopt the new taxonomy when authoring the multi-domain corpus expansion — tagging by trade-off shape (cube scope/distance/authority), not by subject surface (guards AP3).
  • team-dynamics narrows in scope. New scenarios use the tightened definition; existing scenarios are already work-shaped so no forced reclassification, but a future audit may choose to re-tag any borderline interpersonal scenarios that should now read as relational-decision.
  • resource-allocation framing widens to admit personal-resource scenarios.
  • No migration, no signal-aggregate change, no category_patterns shape change. Existing profiles are unperturbed (verified in calculateModelConfidence).
  • Open trigger-conditions for re-audit:
  • (a) When R1 lands (E5/E7 by_expertise breakout, = schema Q4d) → revisit AP1, the per-category risk_tolerance scalar: retire it from exposure or annotate it with the expertise split.
  • (b) When scenario authors push back on health tagging during corpus work → revisit the deferred health_decision_point trigger.
  • (c) R2 (physical attention sub-category) → evaluate when corpus shows a distinct physical-attention signal.

Key files: - docs/research/briefs/multi-domain-category-taxonomy-brief.md — the source analysis (commit 0877066) - docs/decisions/074-pulse-as-multi-domain-judgment-layer.md — the parent ADR this expands - docs/decisions/024-judgment-layer-signals.md — signal architecture; confirms the 14 signals stay - docs/research/foundations/measurement-schema.md — architectural-independence finding ("categories compose additively without conflict") - docs/research/foundations/measurement-schema-readers-guide.md — plain-language schema explainer - docs/research/foundations/scenario-dimension-cube.md — cube-C1/C2, scope/distance/authority axes used in the category definitions - docs/research/experiments/experiment-new-domain-signals.md — Finding 1 (expertise-conditional calibration/persuadability) and the E13/E14 signal discoveries - src/lib/ai/scenario-generator.tsScenarioCategory union (line 14), validCategories, prompt strings - src/lib/ai/driver-trigger-constants.tsTRIGGERS array (add personal_crossroads, intimate_disclosure) - src/types/database.tscategory_patterns shape (line 948), ScenarioCategory references - src/lib/ai/player-model.tsupdateCategoryPatterns, migrateProfile, calculateModelConfidence (additivity verified here)