Skip to content

namegen: per-placeholder gender override unreliably contaminates cascade for sibling cascade-aware slots #69

@serelon

Description

@serelon

Summary

When a format string mixes a per-placeholder gender override ({slot:male} / {slot:female}) with cascade-aware slots, the override sometimes contaminates the gender cascade for other slots in the same format. Behavior is probabilistic — sometimes the cascade is preserved, sometimes the override wins.

The guide states (references/nameset-guide.md):

The override is per-placeholder; the cascade still applies to other slots.

The observed behavior contradicts this.

Repro

Nameset (simplified — kin category cascades on gender, firstName includes both genders + unisex):

{
  "namespace": "test",
  "id": "patronym-bug",
  "genderWeights": {"male": 50, "female": 50},
  "formats": {
    "patronym": {"template": "{firstName} {kin} of {firstName:male}"}
  },
  "nameCategories": {
    "firstName": [
      {"name": "Hild", "gender": "female"},
      {"name": "Halric", "gender": "male"},
      {"name": "Ragnhild", "gender": "female"},
      {"name": "Bran", "gender": "male"}
    ],
    "kin": [
      {"name": "son", "gender": "male"},
      {"name": "daughter", "gender": "female"}
    ]
  }
}

Generate ~8 names. Sample output (real, from the-silence:rathenmoor with the same format):

Targ son of Wulfric         ← cascade=male, OK
Edwyn daughter of Heldric   ← cascade=female, OK
Hild son of Halvar          ← Hild is female-tagged, but kin = son ✗
Jarl son of Harald          ← cascade=male, OK
Botric son of Marn          ← cascade=male, OK
Ragnhild son of Thelric     ← Ragnhild is female-tagged, but kin = son ✗

Expected: when {firstName} rolls female, {kin} should roll female (daughter).

Actual: cascade for {kin} is sometimes overridden to male — appears to be influenced by the {firstName:male} override on the parent slot.

Reordering placeholders ({kin} before {firstName:male}) did not reliably help. The bug is intermittent, suggesting the cascade gender state is being mutated by override resolution rather than overrides being scoped per-placeholder.

Workaround

Split into two explicit formats with overrides on every slot — no cascade-aware slots in the same template as a :male/:female override:

"patronym-son":      {"template": "{firstName:male} son of {firstName:male}"},
"patronym-daughter": {"template": "{firstName:female} daughter of {firstName:male}"}

The GM picks via --format. Reliable but loses the cascade-driven mixing.

Suggested fix direction

The per-placeholder override should not mutate the cascade gender state used by other slots — only the slot it appears on. The guide's intent is clear; the implementation appears to leak state.

Environment

  • Discovered while building the-silence:rathenmoor nameset for the Covenant of Hands subsetting in solorpg
  • Python 3.13, Windows
  • rpg-tools commit at the time: develop branch (current submodule HEAD)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions